1. Libraries and functions

1.1 Libraries

Load the required libraries.

library(tidyverse)
library(sf)
library(here)
library(readxl)
library(scales)
library(DT)
library(brms)
library(tidybayes)
library(patchwork)
library(marginaleffects)
library(ggrepel)
library(scico)
library(ggdensity)
library(ggpubr)
library(units)
#library(ggsn)

1.2 Helper functions

Functions that we will use throughout the script

#labeller for years
year_labels <- c(1950:1963)

#The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
#Segment for graphs to match ACF period
acf_start <- decimal_date(ymd("1957-03-11"))
acf_end <- decimal_date(ymd("1957-04-12"))

Function for counterfactual plots



plot_counterfactual <- function(model_data, model, population_denominator, outcome, grouping_var=NULL, re_formula,...){
  
  #labeller for years
  year_labels <- c(1950:1963)

  #The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
  #Segment for graphs to match ACF period
  acf_start <- decimal_date(ymd("1957-03-11"))
  acf_end <- decimal_date(ymd("1957-04-12"))

  summary <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{outcome}}, {{grouping_var}}) %>%
    add_epred_draws({{model}}, re_formula={{re_formula}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
          .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
          .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                  acf_period=="c. post-acf" ~ "Post Intervention"))



  #create the counterfactual (no intervention), and summarise
  
  counterfact <-
    add_epred_draws(object = {{model}},
                    newdata = {{model_data}} %>%
                                  select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, {{outcome}}) %>%
                                  mutate(acf_period = "a. pre-acf"), re_formula={{re_formula}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
         .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
         .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))
  


  #plot the intervention effect
p <- summary %>%
    droplevels() %>%
    ggplot() +
    geom_ribbon(aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
    geom_ribbon(data = counterfact %>% filter(year>=1956), 
                aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
    geom_line(data = counterfact %>% filter(year>=1956), 
              aes(y=.epred_inc, x=year2, colour="Counterfactual")) +
    geom_line(aes(y=.epred_inc, x=year2, group=acf_period,  colour=acf_period)) +
    geom_point(data = {{model_data}}, aes(y={{outcome}}, x=year2, shape=acf_period), size=2) +
    geom_vline(aes(xintercept=acf_end), linetype=3) +
    theme_ggdist() +
    scale_y_continuous(labels=comma, limits = c(0,NA)) +
    scale_x_continuous(labels = year_labels,
                       breaks = year_labels) +
    scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="", na.translate = F) +
    scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="", na.translate = F) +
    scale_shape_discrete(name="", na.translate = F) +
    labs(
      x = "Year",
      y = "Case notification rate (per 100,000)",
      caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
    ) +
    theme(legend.position = "bottom",
          panel.border = element_rect(colour = "grey78", fill=NA),
          title = element_text(size=14),
          axis.text.x = element_text(size=10, angle = 90, hjust=1, vjust=0.5),
          legend.text = element_text(size=12)) +
    guides(shape="none")

    facet_vars <- vars(...)

  if (length(facet_vars) != 0) {
    p <- p + facet_wrap(facet_vars)
  }
  p

}

Function for calculating measures of change over time (RR.peak, RR.level, RR.slope)


summarise_change <- function(model_data, model, population_denominator, grouping_var = NULL, re_formula = NULL) {
  
  #functions for calculating RR.peak
  #i.e. relative case notification rate in 1957 vs. counterfactual trend for 1957
  
  grouping_var <- enquo(grouping_var)
  
  if (!is.null({{grouping_var}})) {
    
    #make the prediction matrix, conditional on whether we want random effects included or not.
    out <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num == 8),
                    acf_period = c("a. pre-acf", "b. acf")
    )
  } else {
    
    out <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num == 8),
                    acf_period = c("a. pre-acf", "b. acf")
    )
  }
  
  peak_draws <- add_epred_draws(newdata = out,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
    mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
    group_by(.draw, !!grouping_var) %>%
    summarise(estimate = last(epred_cnr)/first(epred_cnr)) %>%
    ungroup() %>%
    mutate(measure = "RR.peak")
  
  peak_summary <- peak_draws %>%
    group_by(!!grouping_var) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.peak")
  
  
  #functions for calculating RR.step
  #i.e. relative case notification rate in 1958 vs. counterfactual trend for 1958
  
    if (!is.null({{grouping_var}})) {
    out2 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num == 9),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  } else {
    
    out2 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num == 9),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  }
  
    level_draws <- add_epred_draws(newdata = out2,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
    arrange(y_num, .draw) %>%
    mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
    group_by(.draw, !!grouping_var) %>%
    summarise(estimate = last(epred_cnr)/first(epred_cnr)) %>%
    ungroup() %>%
    mutate(measure = "RR.level")
  
  level_summary <- level_draws %>%
    group_by(!!grouping_var) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.level")
    
    
  #functions for calculating RR.slope
  #i.e. relative change in case notification rate in 1958-1963 vs. counterfactual trend for 1959-1963
  
    if (!is.null({{grouping_var}})) {
    out3 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  } else {
    
    out3 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  }
  
    slope_draws <- add_epred_draws(newdata = out3,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
        arrange(y_num) %>%
        ungroup() %>%
        mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
        group_by(.draw, acf_period, !!grouping_var) %>%
        summarise(slope = (last(epred_cnr) - first(epred_cnr)) / (last(y_num)-first(y_num))) %>%
        ungroup() %>%
        group_by(.draw, !!grouping_var) %>%
        summarise(estimate = last(slope)/first(slope)) %>%
        mutate(measure = "RR.slope")
  
  slope_summary <- slope_draws %>%
     group_by(!!grouping_var) %>%
      median_qi(estimate) %>%
      mutate(measure = "RR.slope")
    
  #gather all the results into a named list
    lst(peak_draws=peak_draws, peak_summary=peak_summary, 
        level_draws=level_draws, level_summary=level_summary, 
        slope_draws=slope_draws, slope_summary=slope_summary)
  
}

Function for calculating difference from counterfactual


calculate_counterfactual <- function(model_data, model, population_denominator, grouping_var=NULL, re_formula=NA){
  
  #effect vs. counterfactual
  counterfact <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf"),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc_counterf = .epred/{{population_denominator}}*100000, .epred_counterf=.epred)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, .draw, .epred_counterf, .epred_inc_counterf, {{grouping_var}})
  
  #Calcuate case notification rate per draw, then summarise.
  post_change <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc = .epred/{{population_denominator}}*100000)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, {{grouping_var}}, .draw, .epred, .epred_inc, {{grouping_var}}) 
  
  #for the overall period
    counterfact_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf"),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, .draw, .epred, {{grouping_var}})  %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred_counterf = sum(.epred)) 
  
  #Calcuate case notification rate per draw, then summarise.
  post_change_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, {{grouping_var}}, .draw, .epred) %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred = sum(.epred)) 
  
  
counter_post <-
  left_join(counterfact, post_change) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf,
           diff_inc100k = .epred_inc - .epred_inc_counterf,
           rr_inc100k = .epred_inc/.epred_inc_counterf) %>%
    group_by(year, {{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change, diff_inc100k, rr_inc100k) %>%
    ungroup()

counter_post_overall <-
  left_join(counterfact_overall, post_change_overall) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by({{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup()

lst(counter_post, counter_post_overall)

}

Function for tidying up counterfactuals (mostly for making nice tables)


tidy_counterfactuals <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"),
            diff_inc = glue::glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr_inc = glue::glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"))
}


tidy_counterfactuals_overall <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"))
}

2. Data

Import datasets for analysis

2.1 Shapefiles

Make a map of Glasgow wards


glasgow_wards_1951 <- st_read(here("mapping/glasgow_wards_1951.geojson"))
Reading layer `glasgow_wards_1951' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/glasgow_wards_1951.geojson' 
  using driver `GeoJSON'
Simple feature collection with 37 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -4.393502 ymin: 55.77464 xmax: -4.070411 ymax: 55.92814
Geodetic CRS:  WGS 84

#read in Scotland boundary
scotland <- st_read(here("mapping/Scotland_boundary/Scotland boundary.shp"))
Reading layer `Scotland boundary' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/Scotland_boundary/Scotland boundary.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5513 ymin: 530249 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
#make a bounding box for Glasgow
bbox <- st_bbox(glasgow_wards_1951) |> st_as_sfc()

#plot scotland with a bounding box around the City of Glasgow
scotland_with_bbox <- ggplot() +
  geom_sf(data = scotland, fill="antiquewhite") +
  geom_sf(data = bbox, colour = "#C60C30", fill="antiquewhite") +
  theme_void() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "#EAF7FA", size = 0.3))

#plot the wards
#note we tidy up some names to fit on map
glasgow_ward_map <- glasgow_wards_1951 %>%
  mutate(ward = case_when(ward=="Shettleston and Tollcross" ~ "Shettleston and\nTollcross",
                          ward=="Partick (West)" ~ "Partick\n(West)",
                          ward=="Partick (East)" ~ "Partick\n(East)",
                          ward=="North Kelvin" ~ "North\nKelvin",
                          ward=="Kinning Park" ~ "Kinning\nPark",
                          TRUE ~ ward)) %>%
  
  ggplot() +
  geom_sf(aes(fill=division)) +
  geom_sf_label(aes(label = ward), size=3, fill=NA, label.size = NA, colour="black") +
  #scale_colour_identity() +
  scale_fill_brewer(palette = "Set3", name="City of Glasgow Division") +
  theme_grey() +
  labs(x="",
       y="",
       fill="Division") +
  theme(legend.position = "top",
        
        panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "antiquewhite", size = 0.3),
        panel.grid.major = element_line(color = "grey78")) +
  guides(fill=guide_legend(title.position = "top", title.hjust = 0.5, title.theme = element_text(face="bold")))

#add the map of scotland as an inset
glasgow_ward_map + inset_element(scotland_with_bbox, 0.75, 0, 1, 0.4)

ggsave(here("figures/s1.png"), height=10, width = 12)

NA
NA

Calculate areas per geographical unit

sf_use_s2(FALSE) #https://github.com/r-spatial/sf/issues/1762

glasgow_wards_1951 <- glasgow_wards_1951 %>%
  mutate(area = st_area(glasgow_wards_1951))


glasgow_wards_1951$area_km <- units::set_units(glasgow_wards_1951$area, km^2)

Make division shape files, and calculate area (stopped working, need to fix!)


# glasgow_divisions_1951 <- glasgow_wards_1951 %>%
#   group_by(division) %>% 
#   summarize(geometry = st_union(geometry)) %>%
#   nngeo::st_remove_holes() %>%
#   mutate(area = st_area(glasgow_divisions_1951))
# 
# glasgow_divisions_1951$area_km <- units::set_units(glasgow_divisions_1951$area, km^2)

3. Denominators

Load in the datasets for denonomiators, and check for consistency.


overall_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "overall_population")

overall_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
overall_pops <- overall_pops %>%
  mutate(year2 = year+0.5)

Note, we have three population estimates:

  1. Population without institutionalised people or people in shipping
  2. Population in institutions
  3. Population in shipping

(Population in shipping is estimated from the 1951 census, so is the same for most years)

3.1 Overall population

First, plot the total population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2), alpha=0.5, colour = "mediumseagreen", fill="mediumseagreen") +
  geom_point(aes(y=total_population, x=year2), colour = "mediumseagreen") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: total population",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

Now the population excluding institutionalised and shipping population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=population_without_inst_ship, x=year2), alpha=0.5, colour = "purple", fill="purple") +
  geom_point(aes(y=population_without_inst_ship, x=year2), colour = "purple") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: population excluding institutionalised and shipping",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

3.2 Population by Ward

There are 5 Divisions containing 37 Wards in the Glasgow Corporation, with consistent boundaries over time.

#look-up table for divisions and wards
ward_lookup <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "divisions_wards")


ward_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "ward_population")

ward_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
ward_pops <- ward_pops %>%
  mutate(year2 = year+0.5)

#Get the Division population
division_pops <- ward_pops %>%
  group_by(division, year) %>%
  summarise(population_without_inst_ship = sum(population_without_inst_ship, na.rm = TRUE),
            institutions = sum(institutions, na.rm = TRUE),
            shipping = sum(shipping, na.rm = TRUE),
            total_population = sum(total_population, na.rm = TRUE))
`summarise()` has grouped output by 'division'. You can override using the `.groups` argument.
division_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Plot the overall population by Division and Ward


division_pops %>%
  mutate(year2 = year+0.5) %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(division~.) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name = "") +
  scale_colour_brewer(palette = "Set3", name = "") +
  labs(
    title = "Glasgow Corporation: total population by Division",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

ward_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(ward~., ncol=6) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name="Division") +
  scale_colour_brewer(palette = "Set3", name = "Division") +
  labs(
    title = "Glasgow City: total population by Ward",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

ggsave(here("figures/s2.png"), height=10, width=12)

Approximately, how many person-years of follow-up do we have?


overall_pops %>%
  ungroup() %>%
  summarise(across(year, length, .names = "years"),
            across(c(population_without_inst_ship, total_population), sum)) %>%
  mutate(across(where(is.double), comma)) %>%
  datatable()
NA
NA

Change in population by ward


ward_pops %>%
  group_by(ward) %>%
  summarise(pct_change_pop = (last(population_without_inst_ship) - first(population_without_inst_ship))/first(population_without_inst_ship)) %>%
  mutate(pct_change_pop = percent(pct_change_pop)) %>%
  arrange(pct_change_pop) %>%
  datatable()
NA
NA
NA

Output population density by ward and divison for regression modelling

Wards first

(stopped working, need to fix)


# ward_covariates <-  glasgow_wards_1951 %>%
#   left_join(ward_pops) %>%
#   mutate(people_per_km_sq = as.double(population_without_inst_ship/area_km))
# 
# #plot it out
# 
# ward_covariates %>%
#   ggplot() +
#   geom_sf(aes(fill=people_per_km_sq)) + 
#   facet_wrap(year~., ncol=7) +
#   scale_fill_viridis_c(option="A") +
#   theme(legend.position = "bottom",
#         axis.text.x = element_text(angle = 45, hjust=1))
# 
# ggsave(here("figures/ward_pop_density.png"), width=10)
# 
# write_rds(ward_covariates, here("populations/ward_covariates.rds"))

Now divisions first

(stopped working, need to fix)


# division_covariates <-  glasgow_divisions_1951 %>%
#   left_join(division_pops) %>%
#   mutate(people_per_km_sq = as.double(total_population/area_km))
# 
# #plot it out
# 
# division_covariates %>%
#   ggplot() +
#   geom_sf(aes(fill=people_per_km_sq)) + 
#   geom_sf_label(aes(label = division), size=3, fill=NA, label.size = NA, colour="black", family = "Segoe UI") +
#   facet_wrap(year~., ncol=7) +
#   scale_fill_viridis_c(option="G") +
#   theme(legend.position = "bottom",
#         axis.text.x = element_text(angle = 45, hjust=1))
# 
# ggsave(here("figures/division_pop_density.png"), width=10)
# 
# write_rds(division_covariates, here("populations/division_covariates.rds"))

3.3 Population by age and sex


age_sex <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "age_sex_population") %>%
  pivot_longer(cols = c(male, female),
               names_to = "sex")

#collapse down to smaller age groups to be manageable
age_sex <- age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age == "0 to 4" ~ "00 to 04",
                         age == "5 to 9" ~ "05 to 14",
                         age == "10 to 14" ~ "05 to 14",
                         age == "15 to 19" ~ "15 to 24",
                         age == "20 to 24" ~ "15 to 24",
                         age == "25 to 29" ~ "25 to 34",
                         age == "30 to 34" ~ "25 to 34",
                         age == "35 to 39" ~ "35 to 44",
                         age == "40 to 44" ~ "35 to 44",
                         age == "45 to 49" ~ "45 to 59",
                         age == "50 to 54" ~ "45 to 59",
                         age == "55 to 59" ~ "45 to 59",
                         TRUE ~ "60 & up")) %>%
  group_by(year, age, sex) %>%
  mutate(value = sum(value)) %>%
  ungroup()



m_age_sex <- lm(value ~ splines::ns(year, knots = 3)*age*sex, data = age_sex)

summary(m_age_sex)
Warning: essentially perfect fit: summary may be unreliable

Call:
lm(formula = value ~ splines::ns(year, knots = 3) * age * sex, 
    data = age_sex)

Residuals:
       Min         1Q     Median         3Q        Max 
-2.107e-10 -7.560e-13  0.000e+00  0.000e+00  2.107e-10 

Coefficients: (14 not defined because of singularities)
                                                    Estimate Std. Error    t value Pr(>|t|)    
(Intercept)                                        5.222e+04  3.820e-10  1.367e+14   <2e-16 ***
splines::ns(year, knots = 3)1                     -8.043e+03  7.621e-10 -1.055e+13   <2e-16 ***
splines::ns(year, knots = 3)2                             NA         NA         NA       NA    
age05 to 14                                        3.669e+04  4.679e-10  7.843e+13   <2e-16 ***
age15 to 24                                       -3.893e+03  4.679e-10 -8.320e+12   <2e-16 ***
age25 to 34                                       -3.996e+04  4.679e-10 -8.540e+13   <2e-16 ***
age35 to 44                                       -4.230e+04  4.679e-10 -9.040e+13   <2e-16 ***
age45 to 59                                        5.459e+04  4.411e-10  1.238e+14   <2e-16 ***
age60 & up                                         7.533e+04  4.126e-10  1.826e+14   <2e-16 ***
sexmale                                            3.374e+03  5.402e-10  6.244e+12   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14         -1.863e+03  9.334e-10 -1.996e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24          7.533e+04  9.334e-10  8.070e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34          1.325e+05  9.334e-10  1.420e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44          1.380e+05  9.334e-10  1.479e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59          3.474e+03  8.800e-10  3.948e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up          -8.453e+04  8.232e-10 -1.027e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up                  NA         NA         NA       NA    
splines::ns(year, knots = 3)1:sexmale             -1.994e+03  1.078e-09 -1.850e+12   <2e-16 ***
splines::ns(year, knots = 3)2:sexmale                     NA         NA         NA       NA    
age05 to 14:sexmale                                1.053e+04  6.617e-10  1.592e+13   <2e-16 ***
age15 to 24:sexmale                                2.352e+04  6.617e-10  3.555e+13   <2e-16 ***
age25 to 34:sexmale                                1.355e+04  6.617e-10  2.047e+13   <2e-16 ***
age35 to 44:sexmale                               -1.727e+03  6.617e-10 -2.611e+12   <2e-16 ***
age45 to 59:sexmale                                2.774e+03  6.238e-10  4.446e+12   <2e-16 ***
age60 & up:sexmale                                -7.761e+04  5.835e-10 -1.330e+14   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14:sexmale -2.049e+04  1.320e-09 -1.552e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24:sexmale -6.780e+04  1.320e-09 -5.136e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34:sexmale -3.804e+04  1.320e-09 -2.882e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44:sexmale -1.171e+04  1.320e-09 -8.874e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59:sexmale -3.473e+04  1.244e-09 -2.791e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up:sexmale   1.056e+05  1.164e-09  9.071e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up:sexmale          NA         NA         NA       NA    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 5.755e-11 on 44 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 1.714e+29 on 27 and 44 DF,  p-value: < 2.2e-16
age_levels <- age_sex %>% select(age) %>% distinct() %>% pull() 

age_sex_nd <- 
  crossing(
    age=age_levels,
    sex=c("male", "female"),
    year = 1950:1963
  )

pred_pops <- age_sex_nd %>% modelr::add_predictions(m_age_sex)
Warning: prediction from rank-deficient fit; attr(*, "non-estim") has doubtful cases
pred_pops %>%
  ggplot(aes(x=year, y=pred, colour=age)) +
  geom_line() +
  geom_point() +
  facet_grid(sex~.) +
  scale_y_continuous(labels = comma, limits = c(0, 125000))


#How well do they match up with our overall populations?
pred_pops %>%
  group_by(year) %>%
  summarise(sum_pred_pop = sum(pred)) %>%
  right_join(overall_pops) %>%
  select(year, sum_pred_pop, population_without_inst_ship, total_population) %>%
  pivot_longer(cols = c(sum_pred_pop, population_without_inst_ship, total_population)) %>%
  ggplot(aes(x=year, y=value, colour=name)) +
  geom_point() +
  scale_y_continuous(labels = comma, limits = c(800000, 1250000))
Joining with `by = join_by(year)`

pred_pops %>%
  group_by(year, sex) %>%
  summarise(sum = sum(pred)) %>%
  group_by(year) %>%
  mutate(sex_ratio = first(sum)/last(sum))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.

What percentage of adults (15+ participated in the intervention in 1957)?


pred_pops %>%
  ungroup() %>%
  filter(year==1957) %>%
  filter(age != "00 to 04",
         age != "05 to 14") %>%
  summarise(total_pop = sum(pred)) %>%
  mutate(cxr_screened = 622349) %>%
  mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))

pred_pops %>%
  ungroup() %>%
  filter(year==1957) %>%
  filter(age != "00 to 04",
         age != "05 to 14") %>%
  summarise(total_pop = sum(pred), .by=sex) %>%
  mutate(cxr_screened = c(340474, 281875)) %>%
  mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))
NA
NA

Population pyramids


label_abs <- function(x) {
  comma(abs(x))
}


pred_pops %>%
  ungroup() %>%
  group_by(year) %>%
  mutate(year_pop = sum(pred),
         age_sex_pct = percent(pred/year_pop, accuracy=0.1)) %>%
  mutate(sex = case_when(sex=="male" ~ "Male",
                         sex=="female" ~ "Female")) %>%
  ggplot(
    aes(x = age, fill = sex, 
        y = ifelse(test = sex == "Female",yes = -pred, no = pred))) + 
  geom_bar(stat = "identity") +
  geom_text(aes(label = age_sex_pct),
            position= position_stack(vjust=0.5), colour="white", size=2.5) +
  facet_wrap(year~., ncol=7) +
  coord_flip() +
  scale_y_continuous(labels = label_abs) +
  scale_fill_manual(values = c("mediumseagreen", "purple"), name="") +
  theme_ggdist() +
  theme(axis.text.x = element_text(angle=90, hjust = 1, vjust=0.5),
        legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="", y="") 


ggsave(here("figures/s3.png"), width=10)
Saving 10 x 4.51 in image

Not perfect, but resonably good. But ahhhhh… the age groups don’t align with the case notification age groups! Come back to think about this later.

4. Tuberculosis cases

Import the tuberculosis cases dataset

4.1 Overall notifications

Overall, by year.


cases_by_year <- read_xlsx("2023-11-28_glasgow-acf.xlsx", sheet = "by_year")

cases_by_year%>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


#shift year to midpoint
cases_by_year <- cases_by_year %>%
  mutate(year2 = year+0.5)

Plot the overall number of case notified per year, by pulmonary and extra pulmonary classification.


cases_by_year %>%
  select(-total_notifications, -year) %>%
  pivot_longer(cols = c(pulmonary_notifications, `non-pulmonary_notifications`)) %>%
  mutate(name = case_when(name == "pulmonary_notifications" ~ "Pulmonary TB",
                          name == "non-pulmonary_notifications" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

4.2 Notifications by Division

Read in the datasets and merge together.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
ward_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_ward", value)) %>%
  pull(value)


cases_by_ward_sex_year <- map_df(ward_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_ward_sex_year %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Aggregate together to get cases by division


cases_by_division <- cases_by_ward_sex_year %>%
  left_join(ward_lookup) %>%
  group_by(division, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE))
Joining with `by = join_by(ward)``summarise()` has grouped output by 'division', 'year'. You can override using the `.groups` argument.
#shift year to midpoint
cases_by_division <- cases_by_division %>%
  mutate(year2 = year+0.5) %>%
  ungroup()

cases_by_division  %>%
  select(-year2) %>%
  select(year, everything()) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


cases_by_division %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

4.3 Notifications by ward



cases_by_ward <- cases_by_ward_sex_year %>%
  group_by(ward, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE)) %>%
  ungroup()
`summarise()` has grouped output by 'ward', 'year'. You can override using the `.groups` argument.
cases_by_ward %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  select(year, everything()) %>%
  datatable()

#shift year to midpoint
cases_by_ward <- cases_by_ward %>%
  mutate(year2 = year+0.5)

cases_by_ward %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.8) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA

4.4 Notifications by age and sex

As we don’t have denominators, we will just model the change in counts.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
age_sex_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_age_sex", value)) %>%
  pull(value)


cases_by_age_sex <- map_df(age_sex_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_age_sex %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA

5 TB case notification rates

5.1 Overall TB case notification rates

Now calculate case notification rates per 100,000 population

Merge the notification and population denominator datasets together.

Here we need to include the whole population (with shipping and institutions) as they are included in the notifications.


overall_inc <- overall_pops %>%
  left_join(cases_by_year)
Joining with `by = join_by(year, year2)`
overall_inc <- overall_inc %>%
  mutate(inc_pulm_100k = pulmonary_notifications/total_population*100000,
         inc_ep_100k = `non-pulmonary_notifications`/total_population*100000,
         inc_100k = total_notifications/total_population*100000)

overall_inc %>%
  select(year, inc_100k, inc_pulm_100k, inc_ep_100k) %>%
  mutate_at(.vars = vars(inc_100k, inc_pulm_100k, inc_ep_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

overall_inc %>%
  select(year2, inc_pulm_100k, inc_ep_100k) %>%
  pivot_longer(cols = c(inc_pulm_100k, `inc_ep_100k`)) %>%
  mutate(name = case_when(name == "inc_pulm_100k" ~ "Pulmonary TB",
                          name == "inc_ep_100k" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB case notification rates by Division


division_inc <- division_pops %>%
  left_join(cases_by_division)
Joining with `by = join_by(division, year)`
division_inc <- division_inc %>%
  mutate(inc_100k = cases/total_population*100000)

division_inc %>%
  select(year, division, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

division_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB case notification rates by Ward

Here we will filter out the institutions and harbour from the denominators, as we don’t have reliable population denominators for them.


ward_inc <- ward_pops %>%
  left_join(cases_by_ward)
Joining with `by = join_by(ward, year, year2)`
ward_inc <- ward_inc %>%
  mutate(inc_100k = cases/population_without_inst_ship*100000)

ward_inc %>%
  select(year, ward, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

ward_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Incidence (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA
NA
NA

On a map


st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(legend.position = "top",
        legend.key.width = unit(2, "cm"),
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`

6. TB Mortality

6.1 Overall Mortality

Import the TB mortality data.

First, overall deaths. Note that in the original reports, we have a pulmonary TB death rate per million for all years, and numbers of pulmonary TB deaths for each year apart from 1950.


#get the overall mortality sheets
deaths_sheets <- enframe(all_sheets) %>%
  filter(grepl("deaths", value)) %>%
  pull(value)


overall_deaths <- map_df(deaths_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

overall_deaths %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA
NA

Plot the raw numbers of pulmonary deaths


overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_deaths)) +
  geom_line(colour = "#DE0D92") +
  geom_point(colour = "#DE0D92") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  labs(y="Pulmonary TB deaths per year",
       x = "Year",
       title = "Numbers of pulmonary TB deaths",
       subtitle = "Glasgow, 1950-1963",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: no data for 1950") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

NA
NA

Now the incidence of pulmonary TB death

overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_death_rate_per_100k)) +
  geom_line(colour = "#4D6CFA") +
  geom_point(colour = "#4D6CFA") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(y="Annual incidence of death (per 100,000)",
       x = "Year",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s7.png"), width=10)
Saving 10 x 4.51 in image

6. Table 1

Make Table 1 here, and save for publication.


overall_pops %>% 
  select(year, total_population) %>%
  left_join(overall_inc %>%
              select(year, 
                     pulmonary_notifications, inc_pulm_100k,
                     `non-pulmonary_notifications`, inc_ep_100k,
                     total_notifications, inc_100k)) %>%
  left_join(overall_deaths %>%
              select(year,
                     pulmonary_deaths, pulmonary_death_rate_per_100k)) %>%
  mutate(across(where(is.numeric) & !(year),  ~round(., digits=1))) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) 
Joining with `by = join_by(year)`Joining with `by = join_by(year)`

Prepare the datasets for modelling


mdata <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

mdata_extrapulmonary <- ward_inc %>%
  filter(tb_type=="Non-Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()


#scaffold for overall predictions
overall_scaffold <- mdata %>%
    select(year, year2, y_num, acf_period, population_without_inst_ship, ward, cases) %>%
    group_by(year, year2, y_num, acf_period) %>%
    summarise(population_without_inst_ship = sum(population_without_inst_ship),
              cases = sum(cases)) %>%
    ungroup() %>%
    mutate(inc_100k = cases/population_without_inst_ship*100000) %>%
    left_join(mdata_extrapulmonary %>% group_by(year) %>%
                summarise(cases_extrapulmonary = sum(cases))) %>%
    mutate(inc_100k_extrapulmonary = cases_extrapulmonary/population_without_inst_ship*100000)
`summarise()` has grouped output by 'year', 'year2', 'y_num'. You can override using the `.groups` argument.Joining with `by = join_by(year)`

7. Pulmonary TB model

7.1 Fit the model and priors

This models the case notification rate over time, with a step change for the intervention, and slope change after the intervention.

Work on the priors a bit. We will build up from less complex to more complex.

  1. intercept only, to predict count of cases

at the intercept, we expect somewhere around 2500. We will set the standard deviation to both 0.5 and 1 to check what it looks like


c(prior(lognormal(7.600902, 0.5)), #log(2500) = 7.600902
  prior(lognormal(7.600902, 1))) %>% 
  parse_dist() %>% 
  
  ggplot(aes(y = prior, dist = .dist, args = .args)) +
  stat_halfeye(.width = c(.5, .95)) +
  scale_y_discrete(NULL, labels = str_c("lognormal(log(2000), ", c(0.5, 1), ")"),
                   expand = expansion(add = 0.1)) +
  xlab(expression(exp(italic(p)(beta[0])))) +
  coord_cartesian(xlim = c(0,15000))



prior(gamma(1, 0.01)) %>%
  parse_dist() %>%
  ggplot(aes(y=prior, dist = .dist, args = .args)) +
  stat_halfeye(.width = c(0.5, 0.95))


#now fit to a model, and plot some prior realisations

m_prior1 <- brm(
  cases ~ 0 + Intercept,
  family = negbinomial(),
  data = overall_scaffold,
  sample_prior = "only",
  prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
          prior(gamma(1, 0.01), class = shape)
)
Compiling Stan program...
Start sampling

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 2.5e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.25 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 0.009 seconds (Warm-up)
Chain 1:                0.006 seconds (Sampling)
Chain 1:                0.015 seconds (Total)
Chain 1: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 1e-06 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.01 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 0.006 seconds (Warm-up)
Chain 2:                0.007 seconds (Sampling)
Chain 2:                0.013 seconds (Total)
Chain 2: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 0 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 0.006 seconds (Warm-up)
Chain 3:                0.006 seconds (Sampling)
Chain 3:                0.012 seconds (Total)
Chain 3: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 0 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 0.006 seconds (Warm-up)
Chain 4:                0.006 seconds (Sampling)
Chain 4:                0.012 seconds (Total)
Chain 4: 
add_epred_draws(object=m_prior1,
                newdata = tibble(intercept=1)) %>%
  ggplot(aes(x=intercept, y=.epred)) +
  stat_halfeye() +
  scale_y_log10(labels = comma)

NA
NA

Now try to add in a term for the effect of y_num. We anticpate that the number of cases will decline by about 1-5% per year. However, as we are pretty uncertain about this, we will just encode a weakly regularising prior to restrict the year size to sensible ranges.



m_prior2 <- brm(
  cases ~ 0 + Intercept + y_num,
  family = negbinomial(),
  data = overall_scaffold,
  sample_prior = "only",
  prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
          prior(gamma(1, 0.01), class = shape) +
          prior(normal(0, 0.01), class = b, coef = y_num)
)
Compiling Stan program...
Start sampling

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 2.2e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.22 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 0.018 seconds (Warm-up)
Chain 1:                0.007 seconds (Sampling)
Chain 1:                0.025 seconds (Total)
Chain 1: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 1e-06 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.01 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 0.017 seconds (Warm-up)
Chain 2:                0.008 seconds (Sampling)
Chain 2:                0.025 seconds (Total)
Chain 2: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 2e-06 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.02 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 0.016 seconds (Warm-up)
Chain 3:                0.007 seconds (Sampling)
Chain 3:                0.023 seconds (Total)
Chain 3: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 2e-06 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.02 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 0.018 seconds (Warm-up)
Chain 4:                0.007 seconds (Sampling)
Chain 4:                0.025 seconds (Total)
Chain 4: 
add_epred_draws(object=m_prior2,
                newdata = overall_scaffold) %>%
  ggplot(aes(x=year, y=.epred)) +
  stat_halfeye() +
  scale_y_log10(label=comma)

Now we want to add in a prior for the effect of the acf_intervention. We anticipate the peak to be anywhere between no effect, and a tripling


m_prior3 <- brm(
  cases ~ 0 + Intercept + y_num + acf_period,
  family = negbinomial(),
  data = overall_scaffold,
  sample_prior = "only",
  prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
          prior(gamma(1, 0.01), class = shape) +
          prior(normal(0, 0.01), class = b, coef = y_num) +
          prior(normal(0, 0.001), class = b)
)
Compiling Stan program...
Start sampling

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 2.2e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.22 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 0.061 seconds (Warm-up)
Chain 1:                0.014 seconds (Sampling)
Chain 1:                0.075 seconds (Total)
Chain 1: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 1e-06 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.01 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 0.053 seconds (Warm-up)
Chain 2:                0.013 seconds (Sampling)
Chain 2:                0.066 seconds (Total)
Chain 2: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 1e-06 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.01 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 0.042 seconds (Warm-up)
Chain 3:                0.014 seconds (Sampling)
Chain 3:                0.056 seconds (Total)
Chain 3: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 1e-06 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.01 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 0.057 seconds (Warm-up)
Chain 4:                0.013 seconds (Sampling)
Chain 4:                0.07 seconds (Total)
Chain 4: 
add_epred_draws(object=m_prior3,
                newdata = overall_scaffold) %>%
  ggplot(aes(x=year, y=.epred)) +
  stat_halfeye() +
  scale_y_log10(labels = comma)

NA
NA
NA

Now we look and see what it looks like with the interactions


m_prior4 <- brm(
  cases ~ 0 + Intercept + y_num + acf_period + y_num:acf_period,
  family = negbinomial(),
  data = overall_scaffold,
  sample_prior = "only",
  prior = prior(normal(log(2500), 1), class = b, coef = Intercept) +
          prior(gamma(1, 0.01), class = shape) +
          prior(normal(0, 0.01), class = b)
)
Compiling Stan program...
Start sampling

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 2.2e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.22 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 0.026 seconds (Warm-up)
Chain 1:                0.011 seconds (Sampling)
Chain 1:                0.037 seconds (Total)
Chain 1: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 1e-06 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.01 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 0.024 seconds (Warm-up)
Chain 2:                0.01 seconds (Sampling)
Chain 2:                0.034 seconds (Total)
Chain 2: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 1e-06 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.01 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 0.023 seconds (Warm-up)
Chain 3:                0.01 seconds (Sampling)
Chain 3:                0.033 seconds (Total)
Chain 3: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 1e-06 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.01 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 0.021 seconds (Warm-up)
Chain 4:                0.01 seconds (Sampling)
Chain 4:                0.031 seconds (Total)
Chain 4: 
add_epred_draws(object=m_prior4,
                newdata = overall_scaffold) %>%
  ggplot(aes(x=year, y=.epred)) +
  stat_halfeye() +
  scale_y_log10(label=comma)

NA
NA
NA

Now try adding in the random intercepts


c(prior(lognormal(3.912023, 0.5)), #log(50) = 3.912023
  prior(lognormal(3.912023, 1))) %>% 
  parse_dist() %>% 
  
  ggplot(aes(y = prior, dist = .dist, args = .args)) +
  stat_halfeye(.width = c(.5, .95)) +
  scale_y_discrete(NULL, labels = str_c("lognormal(log(50), ", c(0.5, 1), ")"),
                   expand = expansion(add = 0.1)) +
  xlab(expression(exp(italic(p)(beta[0])))) +
  coord_cartesian(xlim = c(0,400))



m_prior5 <- brm(
  cases ~ y_num + acf_period + y_num:acf_period + ( 1 | ward),
  family = negbinomial(),
  data = mdata,
  sample_prior = "only",
  prior = prior(normal(log(50), 1), class = Intercept) +
          prior(gamma(1, 0.01), class = shape) +
          prior(normal(0, 0.01), class = b) +
          prior(exponential(1), class=sd)
)
Compiling Stan program...
Start sampling

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 6.1e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.61 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 0.148 seconds (Warm-up)
Chain 1:                0.04 seconds (Sampling)
Chain 1:                0.188 seconds (Total)
Chain 1: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 3e-06 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.03 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 0.143 seconds (Warm-up)
Chain 2:                0.042 seconds (Sampling)
Chain 2:                0.185 seconds (Total)
Chain 2: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 4e-06 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.04 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 0.149 seconds (Warm-up)
Chain 3:                0.035 seconds (Sampling)
Chain 3:                0.184 seconds (Total)
Chain 3: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 4e-06 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.04 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 0.151 seconds (Warm-up)
Chain 4:                0.028 seconds (Sampling)
Chain 4:                0.179 seconds (Total)
Chain 4: 
add_epred_draws(object=m_prior5,
                newdata = mdata,
                re_formula = NA) %>%
  ggplot(aes(x=year, y=.epred)) +
  stat_halfeye() +
  scale_y_log10(label=comma)


add_epred_draws(object=m_prior5,
                newdata = mdata,
                re_formula = NA) %>%
  ggplot(aes(x=year, y=.epred)) +
  stat_halfeye() +
  scale_y_log10(label=comma) +
  facet_wrap(ward~.)

And add in the random slopes


m_prior6 <- brm(
  cases ~ 1 + y_num + acf_period + y_num:acf_period + (1 + y_num*acf_period | ward),
  family = negbinomial(),
  data = mdata,
  sample_prior = "only",
  prior = prior(gamma(1, 0.01), class = shape) +
          prior(normal(0, 0.1), class = b) +
          prior(exponential(1), class=sd) +
          prior(lkj(2), class=cor)
)
Compiling Stan program...
Start sampling

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 7.7e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.77 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 0.209 seconds (Warm-up)
Chain 1:                0.173 seconds (Sampling)
Chain 1:                0.382 seconds (Total)
Chain 1: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 1e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 0.202 seconds (Warm-up)
Chain 2:                0.178 seconds (Sampling)
Chain 2:                0.38 seconds (Total)
Chain 2: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 1e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 0.203 seconds (Warm-up)
Chain 3:                0.171 seconds (Sampling)
Chain 3:                0.374 seconds (Total)
Chain 3: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 1e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 0.213 seconds (Warm-up)
Chain 4:                0.171 seconds (Sampling)
Chain 4:                0.384 seconds (Total)
Chain 4: 
m_prior6 <- brm(
  cases ~ 0 + Intercept + y_num + acf_period + y_num:acf_period + ( y_num*acf_period | ward),
  family = negbinomial(),
  data = mdata,
  sample_prior = "only",
  prior = prior(normal(log(50), 1), class = b, coef = Intercept) +
          prior(gamma(1, 0.01), class = shape) +
          prior(normal(0, 0.01), class = b) +
          prior(exponential(100), class=sd) +
          prior(lkj(2), class=cor)
)
Compiling Stan program...
Start sampling

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 6.4e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.64 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 0.545 seconds (Warm-up)
Chain 1:                0.174 seconds (Sampling)
Chain 1:                0.719 seconds (Total)
Chain 1: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 9e-06 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 0.541 seconds (Warm-up)
Chain 2:                0.168 seconds (Sampling)
Chain 2:                0.709 seconds (Total)
Chain 2: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 9e-06 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.09 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 0.557 seconds (Warm-up)
Chain 3:                0.169 seconds (Sampling)
Chain 3:                0.726 seconds (Total)
Chain 3: 

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 1e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.1 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 0.571 seconds (Warm-up)
Chain 4:                0.169 seconds (Sampling)
Chain 4:                0.74 seconds (Total)
Chain 4: 
add_epred_draws(object=m_prior6,
                newdata = mdata,
                re_formula = NA) %>%
  ggplot(aes(x=year, y=.epred)) +
  stat_halfeye() +
  scale_y_log10(label=comma)


add_epred_draws(object=m_prior6,
                newdata = mdata,
                re_formula = ~( 1 + y_num + acf_period | ward)) %>%
  ggplot(aes(x=year, y=.epred)) +
  stat_halfeye() +
  scale_y_log10(label=comma) +
  facet_wrap(ward~.)


plot_counterfactual(model_data = overall_scaffold, model=m_prior6, outcome = inc_100k, 
                    population_denominator = population_without_inst_ship, re_formula = NA)


plot_counterfactual(model_data = mdata, model=m_prior6, outcome = inc_100k, 
                    population_denominator = population_without_inst_ship, grouping_var = ward, ward,
                    re_formula = ~( 1 + y_num + acf_period | ward))

Issue here is the non-centred parameterisation of the intercept prior… Feel like this is a more interpretable way to set priors… but will revert to centred parameterisation for the meantime.

Look at the mean and variance of counts (counts of pulmonary notifications are what we are predicting)


#Mean of counts per year
mean(mdata$cases)
[1] 48.32819
#variance of counts per year
var(mdata$cases)
[1] 915.5749

Quite a bit of over-dispersion here, so negative binomial distribution might be a better choice of distributional family than Poisson.

Fit the model with the data


m_pulmonary <- brm(
  cases ~ y_num + acf_period + y_num:acf_period + (y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
                  data = mdata,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4,
                  prior = prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 0.1), class = b) +
                          prior(exponential(1), class=sd) +
                          prior(lkj(2), class=cor))
Compiling Stan program...
Start sampling
starting worker pid=54171 on localhost:11231 at 11:12:13.446
starting worker pid=54184 on localhost:11231 at 11:12:13.540
starting worker pid=54197 on localhost:11231 at 11:12:13.632
starting worker pid=54210 on localhost:11231 at 11:12:13.723

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 0.000167 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 1.67 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 0.000174 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 1.74 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 0.00016 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 1.6 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 0.000173 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 1.73 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 8.819 seconds (Warm-up)
Chain 2:                4.58 seconds (Sampling)
Chain 2:                13.399 seconds (Total)
Chain 2: 
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 9.956 seconds (Warm-up)
Chain 1:                4.483 seconds (Sampling)
Chain 1:                14.439 seconds (Total)
Chain 1: 
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 10.015 seconds (Warm-up)
Chain 3:                4.216 seconds (Sampling)
Chain 3:                14.231 seconds (Total)
Chain 3: 
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 10.638 seconds (Warm-up)
Chain 4:                4.522 seconds (Sampling)
Chain 4:                15.16 seconds (Total)
Chain 4: 
Warning: There were 89 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them.Warning: Examine the pairs() plot to diagnose sampling problems
Warning: Tail Effective Samples Size (ESS) is too low, indicating posterior variances and tail quantiles may be unreliable.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#tail-ess
  
#check model diagnostics
summary(m_pulmonary)
Warning: There were 89 divergent transitions after warmup. Increasing adapt_delta above 0.8 may help. See http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + acf_period + y_num:acf_period + (y_num * acf_period | ward) + offset(log(population_without_inst_ship)) 
   Data: mdata (Number of observations: 518) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Group-Level Effects: 
~ward (Number of levels: 37) 
                                                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)                                             0.26      0.04     0.19     0.34 1.00     1200     1623
sd(y_num)                                                 0.02      0.01     0.01     0.03 1.01      675      702
sd(acf_periodb.acf)                                       0.07      0.05     0.00     0.18 1.01      935      859
sd(acf_periodc.postMacf)                                  0.13      0.07     0.01     0.28 1.01      475      257
sd(y_num:acf_periodb.acf)                                 0.01      0.01     0.00     0.02 1.00     1121     1892
sd(y_num:acf_periodc.postMacf)                            0.01      0.01     0.00     0.03 1.01      423      227
cor(Intercept,y_num)                                     -0.50      0.20    -0.81    -0.03 1.00     2182     1496
cor(Intercept,acf_periodb.acf)                           -0.27      0.33    -0.79     0.43 1.00     2352     1616
cor(y_num,acf_periodb.acf)                               -0.07      0.32    -0.64     0.57 1.00     2118     1756
cor(Intercept,acf_periodc.postMacf)                      -0.17      0.28    -0.66     0.41 1.00     3212     2728
cor(y_num,acf_periodc.postMacf)                           0.14      0.30    -0.46     0.67 1.00     2555     2649
cor(acf_periodb.acf,acf_periodc.postMacf)                 0.07      0.33    -0.57     0.68 1.00     1549     2372
cor(Intercept,y_num:acf_periodb.acf)                     -0.28      0.32    -0.80     0.42 1.00     2249     2764
cor(y_num,y_num:acf_periodb.acf)                         -0.06      0.31    -0.63     0.56 1.00     3118     3287
cor(acf_periodb.acf,y_num:acf_periodb.acf)               -0.08      0.34    -0.69     0.59 1.00     3173     1613
cor(acf_periodc.postMacf,y_num:acf_periodb.acf)           0.08      0.33    -0.58     0.67 1.01     1421     1006
cor(Intercept,y_num:acf_periodc.postMacf)                 0.02      0.31    -0.57     0.61 1.00     3214     2272
cor(y_num,y_num:acf_periodc.postMacf)                    -0.09      0.34    -0.68     0.58 1.00      911     1144
cor(acf_periodb.acf,y_num:acf_periodc.postMacf)           0.08      0.33    -0.57     0.68 1.00     1864     2424
cor(acf_periodc.postMacf,y_num:acf_periodc.postMacf)     -0.14      0.37    -0.79     0.57 1.01      827      633
cor(y_num:acf_periodb.acf,y_num:acf_periodc.postMacf)     0.07      0.33    -0.58     0.70 1.00     1006      448

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -6.15      0.05    -6.24    -6.05 1.00      718     1860
y_num                         -0.02      0.01    -0.03    -0.01 1.00     1817     2102
acf_periodb.acf                0.01      0.10    -0.18     0.20 1.00     2039      734
acf_periodc.postMacf           0.02      0.07    -0.12     0.16 1.00     2040     1159
y_num:acf_periodb.acf          0.08      0.01     0.06     0.11 1.00     2199     2991
y_num:acf_periodc.postMacf    -0.05      0.01    -0.07    -0.04 1.00     2374     1217

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    96.60     22.49    62.51   150.08 1.00     1213      979

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_pulmonary)

pp_check(m_pulmonary, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

7.2 Summarise change in CNRs

Summarise the posterior in graphical form


f1b <- plot_counterfactual(model_data = overall_scaffold, model = m_pulmonary, 
                           population_denominator = population_without_inst_ship, outcome = inc_100k, grouping_var=NULL,
                           re_formula = NA)
  
f1b

Make this into a figure combined with the map of empirical data


f1a <- st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "top",
        #legend.key.width = unit(2, "cm"),
        legend.title.align = 0.5) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`
(f1a / f1b) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f1.png"))
Saving 7.29 x 4.51 in image

Summary of change in notifications numerically


overall_change <- summarise_change(model_data=overall_scaffold, model=m_pulmonary, 
                                   population_denominator=population_without_inst_ship, grouping_var=NULL, re_formula = NA)
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
overall_change %>%
  keep((names(.) %in% tokeep)) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA
NA

7.3 Compared to counterfactual

Numbers of pulmonary TB cases averted compared to counterfactual per year.


overall_pulmonary_counterf <- calculate_counterfactual(model_data = overall_scaffold, model=m_pulmonary, population_denominator = population_without_inst_ship)
Joining with `by = join_by(year, population_without_inst_ship, .draw)`Joining with `by = join_by(.draw)`
overall_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

Total pulmonary TB cases averted between 1958 and 1963


overall_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

7.4 Correlation between RR.peak, RR.level, and RR.slope

What are the correlations between peak, level, and slope?


#RR.peak histogram
a <- overall_change$peak_draws %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.peak",
       y="")

#RR. level histogram
b <- overall_change$level_draws  %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.level",
       y="")

#RR.slope histogram
c <- overall_change$slope_draws %>%
  ggplot() +
  geom_histogram(aes(x=estimate), fill="darkblue", colour="darkblue", alpha=0.3)+
  scale_fill_gradient(high="lightblue1",low="darkblue") +  
  scale_x_continuous(limits = c(0, 6)) +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="RR.slope",
       y="")


#Correlation between RR.peak and RR.level
cor_rr_peak_rr_level <- round(cor(pluck(overall_change$peak_draws$estimate), pluck(overall_change$level_draws$estimate)), digits = 2)

#Correlation between RR.peak and RR.slope
cor_rr_peak_rr_slope <- round(cor(pluck(overall_change$peak_draws$estimate), pluck(overall_change$slope_draws$estimate)), digits = 2)

#Correlation between RR.level and RR.slope
cor_rr_level_rr_slope <- round(cor(pluck(overall_change$level_draws$estimate), pluck(overall_change$slope_draws$estimate)), digits = 2)


#plot of correlation between RR.peak and RR.level
d <- bind_cols(RR.peak=pluck(overall_change$peak_draws$estimate), 
          RR.level =pluck(overall_change$level_draws$estimate)) %>%
  ggplot(aes(y=RR.peak, x = RR.level)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick", method = "lm") +
  geom_text(aes(y=2.2, x=0.58, label=cor_rr_peak_rr_level), colour="firebrick")  +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

#plot of correlation between RR.peak and RR.slope
e <- bind_cols(RR.peak=pluck(overall_change$peak_draws$estimate), 
          RR.slope =pluck(overall_change$slope_draws$estimate)) %>%
  ggplot(aes(y=RR.peak, x = RR.slope)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick") +
  geom_text(aes(y=2.1, x=0.5, label=cor_rr_peak_rr_slope), colour="firebrick")  +
  scale_x_continuous(limits = c(0, 6)) +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))

#plot of correlation between RR.level and RR.slope
f <- bind_cols(RR.level=pluck(overall_change$level_draws$estimate), 
          RR.slope =pluck(overall_change$slope_draws$estimate)) %>%
  ggplot(aes(y=RR.level, x = RR.slope)) +
  geom_hex() +
  geom_smooth(se=FALSE, colour="firebrick") +
  geom_text(aes(y=0.75, x=0.5, label=cor_rr_level_rr_slope), colour="firebrick")  +  
  scale_x_continuous(limits = c(0, 6)) +
  scale_fill_gradient(high="lightblue1",low="darkblue") +
  theme_ggdist() +
  theme(legend.position = "none",
        panel.border = element_rect(colour = "grey78", fill=NA))


(plot_spacer() + plot_spacer() + c) /
  (plot_spacer() + b + f) /
  (a + d + e)

ggsave(here("figures/pulmonary_cors.pdf"), width=8, height=8)

NA
NA
NA

7.5 Ward level pulmonary TB estimates

Plot the counterfactual at ward level


plot_counterfactual(model_data = mdata, model=m_pulmonary, outcome = inc_100k, population_denominator = population_without_inst_ship, 
                    grouping_var = ward, ward, re_formula= ~(1 + y_num*acf_period | ward))
  
ggsave(here("figures/s4.png"), width=12, height=12)

Summary of change in notifications at ward level


ward_change <- summarise_change(model_data=mdata, model=m_pulmonary, 
                                   population_denominator=population_without_inst_ship, grouping_var=ward, 
                                   re_formula = ~(1 + y_num*acf_period | ward))
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw', 'acf_period'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
ward_change %>%
  keep((names(.) %in% tokeep)) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA
NA

Calculate the counterfactual per ward


ward_pulmonary_counterf <- calculate_counterfactual(model_data = mdata, model=m_pulmonary, 
                                                    population_denominator = population_without_inst_ship,
                                                    grouping_var = ward, re_formula=~(1 + y_num*acf_period | ward))
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.Joining with `by = join_by(year, population_without_inst_ship, .draw, ward)`Joining with `by = join_by(.draw, ward)`
ward_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

Overall counterfactual per ward


ward_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

8. Extra-pulmonary TB notifications

Now we will model the extra-pulmonary TB notification rate. Struggling a bit with negative binomial model, so revert to Poisson.

8.1 Fit the model


m_extrapulmonary <- brm(
  cases ~ y_num + acf_period + y_num:acf_period + (y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
                  data = mdata_extrapulmonary,
                  family = poisson(),
                  seed = 1234,
                  chains = 4, cores = 4,
                  prior = prior(normal(0, 0.01), class = b) +
                          prior(exponential(1), class=sd) +
                          prior(lkj(2), class=cor))
Compiling Stan program...
Start sampling
starting worker pid=54351 on localhost:11231 at 11:14:18.920
starting worker pid=54364 on localhost:11231 at 11:14:19.008
starting worker pid=54377 on localhost:11231 at 11:14:19.098
starting worker pid=54390 on localhost:11231 at 11:14:19.188

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 0.000137 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 1.37 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 0.000153 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 1.53 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 0.000158 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 1.58 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 0.000152 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 1.52 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 10.74 seconds (Warm-up)
Chain 3:                7.352 seconds (Sampling)
Chain 3:                18.092 seconds (Total)
Chain 3: 
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 17.804 seconds (Warm-up)
Chain 2:                7.331 seconds (Sampling)
Chain 2:                25.135 seconds (Total)
Chain 2: 
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 36.561 seconds (Warm-up)
Chain 4:                18.056 seconds (Sampling)
Chain 4:                54.617 seconds (Total)
Chain 4: 
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 39.242 seconds (Warm-up)
Chain 1:                22.007 seconds (Sampling)
Chain 1:                61.249 seconds (Total)
Chain 1: 
Warning: There were 3 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them.Warning: Examine the pairs() plot to diagnose sampling problems
Warning: Bulk Effective Samples Size (ESS) is too low, indicating posterior means and medians may be unreliable.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#bulk-ess
summary(m_extrapulmonary)
Warning: There were 3 divergent transitions after warmup. Increasing adapt_delta above 0.8 may help. See http://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
 Family: poisson 
  Links: mu = log 
Formula: cases ~ y_num + acf_period + y_num:acf_period + (y_num * acf_period | ward) + offset(log(population_without_inst_ship)) 
   Data: mdata_extrapulmonary (Number of observations: 518) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Group-Level Effects: 
~ward (Number of levels: 37) 
                                                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)                                             0.45      0.10     0.27     0.68 1.00      558     1196
sd(y_num)                                                 0.07      0.02     0.04     0.11 1.00     1113     1391
sd(acf_periodb.acf)                                       0.12      0.09     0.00     0.34 1.00     1885     1771
sd(acf_periodc.postMacf)                                  2.43      0.42     1.70     3.35 1.00     2101     2677
sd(y_num:acf_periodb.acf)                                 0.02      0.01     0.00     0.05 1.00     1982     1754
sd(y_num:acf_periodc.postMacf)                            0.25      0.04     0.17     0.35 1.00     1812     2601
cor(Intercept,y_num)                                     -0.48      0.22    -0.81     0.04 1.00      537     1072
cor(Intercept,acf_periodb.acf)                           -0.08      0.33    -0.68     0.59 1.00     5222     2858
cor(y_num,acf_periodb.acf)                                0.02      0.33    -0.60     0.64 1.00     4841     2729
cor(Intercept,acf_periodc.postMacf)                       0.44      0.23    -0.08     0.81 1.00      434     1041
cor(y_num,acf_periodc.postMacf)                          -0.58      0.17    -0.85    -0.19 1.00     1211     2049
cor(acf_periodb.acf,acf_periodc.postMacf)                -0.11      0.33    -0.71     0.54 1.00      781     2037
cor(Intercept,y_num:acf_periodb.acf)                     -0.09      0.33    -0.68     0.56 1.00     4928     2961
cor(y_num,y_num:acf_periodb.acf)                          0.02      0.33    -0.60     0.65 1.00     4791     2871
cor(acf_periodb.acf,y_num:acf_periodb.acf)               -0.08      0.34    -0.69     0.58 1.00     3271     3208
cor(acf_periodc.postMacf,y_num:acf_periodb.acf)          -0.12      0.33    -0.70     0.53 1.00     3998     3034
cor(Intercept,y_num:acf_periodc.postMacf)                -0.44      0.23    -0.81     0.07 1.00      426     1015
cor(y_num,y_num:acf_periodc.postMacf)                     0.52      0.18     0.11     0.82 1.00     1100     1698
cor(acf_periodb.acf,y_num:acf_periodc.postMacf)           0.13      0.33    -0.53     0.72 1.00      686     1998
cor(acf_periodc.postMacf,y_num:acf_periodc.postMacf)     -0.98      0.01    -1.00    -0.95 1.00     2119     3010
cor(y_num:acf_periodb.acf,y_num:acf_periodc.postMacf)     0.13      0.33    -0.51     0.71 1.00     3593     3169

Population-Level Effects: 
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -8.22      0.16    -8.56    -7.93 1.00      348      744
y_num                         -0.03      0.01    -0.05    -0.01 1.00     2097     2703
acf_periodb.acf               -0.00      0.01    -0.02     0.02 1.00     7349     2986
acf_periodc.postMacf          -0.00      0.01    -0.02     0.02 1.00     6517     3296
y_num:acf_periodb.acf         -0.01      0.01    -0.02     0.01 1.00     5127     3181
y_num:acf_periodc.postMacf    -0.02      0.01    -0.04    -0.00 1.00     2712     3181

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_extrapulmonary)

pp_check(m_extrapulmonary, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

8.2 Summary of change

Summarise in plot

plot_counterfactual(model_data = overall_scaffold, model=m_extrapulmonary, 
                    population_denominator = population_without_inst_ship, outcome=inc_100k_extrapulmonary, re_formula = NA)
  
ggsave(here("figures/s6.png"), width=10)
Saving 10 x 4.51 in image

Summarise numerically.


overall_change_extrapulmonary <- summarise_change(model_data=overall_scaffold, model=m_extrapulmonary, 
                                   population_denominator=population_without_inst_ship, grouping_var=NULL, re_formula = NA)
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
overall_change_extrapulmonary %>%
  keep((names(.) %in% tokeep)) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA

8.3 Compared to counterfactual

Numbers of extra-pulmonary TB cases averted overall.


overall_ep_counterf <- calculate_counterfactual(model_data = mdata, model=m_extrapulmonary, 
                                               population_denominator = population_without_inst_ship)
Joining with `by = join_by(year, population_without_inst_ship, .draw)`Warning: Detected an unexpected many-to-many relationship between `x` and `y`.Joining with `by = join_by(.draw)`
overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

Total extrapulmonary TB cases averted between 1958 and 1963


overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

8.4 Ward-level extra-pulmonary summaries

Ward-level extra-pulmonary estimates in graphical form.


plot_counterfactual(model_data = mdata_extrapulmonary, model=m_extrapulmonary, outcome = inc_100k, 
                    population_denominator = population_without_inst_ship, grouping_var = ward,re_formula =~(y_num*acf_period | ward), 
                    ward)
  
ggsave(here("figures/s4.png"), width=10, height=12)

Numerical summary.


ward_change_extrapulmonary <- summarise_change(model_data = mdata_extrapulmonary, model = m_extrapulmonary, 
                                population_denominator = population_without_inst_ship, grouping_var=ward,
                                re_formula = ~(y_num*acf_period | ward)) 
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw', 'acf_period'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
ward_change_extrapulmonary  %>%
  keep((names(.) %in% tokeep)) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA
NA
NA

9. Age-sex model

9.1 FIt the model

Fit the model

(Not rewritten the functions for this yet)


mdata_age_sex <- cases_by_age_sex %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(year2 = year+0.5) %>%
  group_by(age, sex) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

basic_prior <- c(prior(gamma(1, 0.01), class = shape),
                  prior(normal(0, 1), class = b))


m_age_sex <- brm(
  cases ~ y_num + (acf_period)*(age*sex) + (acf_period:y_num)*(age*sex),
                  data = mdata_age_sex,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = basic_prior)
Compiling Stan program...
Start sampling
starting worker pid=54529 on localhost:11231 at 11:16:17.674
starting worker pid=54542 on localhost:11231 at 11:16:17.767
starting worker pid=54555 on localhost:11231 at 11:16:17.860
starting worker pid=54568 on localhost:11231 at 11:16:17.952

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 3.1e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.31 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 3.4e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.34 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 3.3e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.33 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 3.6e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.36 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 7.56 seconds (Warm-up)
Chain 3:                8.11 seconds (Sampling)
Chain 3:                15.67 seconds (Total)
Chain 3: 
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 7.684 seconds (Warm-up)
Chain 1:                8.421 seconds (Sampling)
Chain 1:                16.105 seconds (Total)
Chain 1: 
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 7.451 seconds (Warm-up)
Chain 2:                8.595 seconds (Sampling)
Chain 2:                16.046 seconds (Total)
Chain 2: 
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 7.648 seconds (Warm-up)
Chain 4:                8.67 seconds (Sampling)
Chain 4:                16.318 seconds (Total)
Chain 4: 
summary(m_age_sex)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + (acf_period) * (age * sex) + (acf_period:y_num) * (age * sex) 
   Data: mdata_age_sex (Number of observations: 224) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Population-Level Effects: 
                                         Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                                    4.42      0.12     4.20     4.64 1.00     1343     2147
y_num                                       -0.17      0.03    -0.23    -0.11 1.00     1252     2227
acf_periodb.acf                             -0.03      1.01    -2.01     1.94 1.00     6912     3214
acf_periodc.postMacf                        -0.49      0.33    -1.15     0.16 1.00     2345     2569
age06_15                                     0.63      0.15     0.33     0.92 1.00     1838     2707
age16_25                                     1.85      0.13     1.59     2.11 1.00     1585     2286
age26_35                                     1.13      0.14     0.87     1.40 1.00     1596     2498
age36_45                                     0.28      0.15    -0.02     0.58 1.00     1769     2775
age46_55                                    -0.62      0.18    -0.97    -0.27 1.00     2008     2581
age56_65                                    -1.08      0.20    -1.47    -0.69 1.00     2489     2473
age65P                                      -1.64      0.22    -2.07    -1.19 1.00     2930     3037
sexM                                         0.16      0.15    -0.14     0.46 1.01     1214     2094
age06_15:sexM                               -0.43      0.21    -0.84    -0.02 1.00     1810     2552
age16_25:sexM                               -0.58      0.18    -0.94    -0.21 1.00     1517     2332
age26_35:sexM                               -0.33      0.19    -0.70     0.03 1.00     1508     2571
age36_45:sexM                                0.24      0.20    -0.15     0.62 1.01     1634     2305
age46_55:sexM                                1.15      0.22     0.73     1.57 1.00     1770     2627
age56_65:sexM                                1.13      0.24     0.67     1.61 1.00     2044     2481
age65P:sexM                                  1.00      0.27     0.46     1.52 1.00     2621     2386
acf_periodb.acf:age06_15                     0.02      0.99    -1.90     1.92 1.00     6941     3409
acf_periodc.postMacf:age06_15               -0.59      0.51    -1.59     0.42 1.00     3773     3033
acf_periodb.acf:age16_25                     0.04      0.98    -1.86     1.92 1.00     8050     2469
acf_periodc.postMacf:age16_25                0.73      0.42    -0.07     1.55 1.00     2881     2749
acf_periodb.acf:age26_35                     0.04      0.96    -1.81     1.89 1.00     6924     3129
acf_periodc.postMacf:age26_35                0.67      0.43    -0.17     1.50 1.00     3245     2773
acf_periodb.acf:age36_45                     0.05      1.02    -2.00     2.07 1.00     6510     2705
acf_periodc.postMacf:age36_45                0.75      0.44    -0.11     1.63 1.00     3353     3352
acf_periodb.acf:age46_55                     0.06      0.98    -1.87     1.99 1.00     6819     3242
acf_periodc.postMacf:age46_55                0.86      0.47    -0.06     1.76 1.00     3571     3272
acf_periodb.acf:age56_65                     0.06      0.98    -1.85     1.94 1.00     7771     3249
acf_periodc.postMacf:age56_65                0.63      0.53    -0.42     1.65 1.00     4063     3040
acf_periodb.acf:age65P                       0.04      0.97    -1.90     1.95 1.00     5912     3120
acf_periodc.postMacf:age65P                  0.98      0.54    -0.06     2.04 1.00     4663     2946
acf_periodb.acf:sexM                        -0.00      0.97    -1.84     1.91 1.00     7446     3131
acf_periodc.postMacf:sexM                   -0.07      0.37    -0.79     0.65 1.00     2992     2737
y_num:acf_periodb.acf                       -0.10      0.13    -0.35     0.16 1.00     6282     3061
y_num:acf_periodc.postMacf                   0.04      0.04    -0.03     0.12 1.00     1706     2258
acf_periodb.acf:age06_15:sexM                0.01      1.00    -1.95     1.98 1.00     7036     2936
acf_periodc.postMacf:age06_15:sexM          -0.56      0.63    -1.77     0.69 1.00     5131     3091
acf_periodb.acf:age16_25:sexM                0.01      1.00    -1.95     1.99 1.00     7013     3319
acf_periodc.postMacf:age16_25:sexM           0.66      0.51    -0.36     1.63 1.00     4498     3216
acf_periodb.acf:age26_35:sexM                0.02      0.98    -1.90     1.95 1.00     7308     2890
acf_periodc.postMacf:age26_35:sexM           0.41      0.52    -0.59     1.46 1.00     3950     3227
acf_periodb.acf:age36_45:sexM                0.00      0.97    -1.87     1.96 1.00     6334     2937
acf_periodc.postMacf:age36_45:sexM           0.12      0.54    -0.96     1.19 1.00     4440     3052
acf_periodb.acf:age46_55:sexM               -0.00      1.00    -1.96     1.99 1.00     8322     2969
acf_periodc.postMacf:age46_55:sexM           0.66      0.54    -0.39     1.73 1.00     4157     3202
acf_periodb.acf:age56_65:sexM                0.02      0.99    -1.89     1.97 1.00     7427     2653
acf_periodc.postMacf:age56_65:sexM           0.36      0.59    -0.80     1.54 1.00     4028     3010
acf_periodb.acf:age65P:sexM                  0.01      1.01    -1.96     2.03 1.00     7489     3096
acf_periodc.postMacf:age65P:sexM             0.28      0.60    -0.89     1.42 1.00     4868     3141
y_num:acf_perioda.preMacf:age06_15           0.02      0.04    -0.05     0.10 1.00     1698     2949
y_num:acf_periodb.acf:age06_15               0.15      0.13    -0.11     0.40 1.00     6254     3314
y_num:acf_periodc.postMacf:age06_15          0.08      0.05    -0.01     0.17 1.00     3265     2929
y_num:acf_perioda.preMacf:age16_25           0.12      0.03     0.06     0.19 1.00     1394     2417
y_num:acf_periodb.acf:age16_25               0.25      0.13    -0.00     0.49 1.00     6965     2970
y_num:acf_periodc.postMacf:age16_25         -0.04      0.04    -0.12     0.04 1.00     2524     2532
y_num:acf_perioda.preMacf:age26_35           0.15      0.03     0.08     0.21 1.00     1481     2509
y_num:acf_periodb.acf:age26_35               0.31      0.13     0.06     0.56 1.00     6429     3105
y_num:acf_periodc.postMacf:age26_35          0.02      0.04    -0.06     0.09 1.00     2849     2826
y_num:acf_perioda.preMacf:age36_45           0.17      0.04     0.10     0.24 1.00     1469     2508
y_num:acf_periodb.acf:age36_45               0.40      0.13     0.14     0.66 1.00     6089     2463
y_num:acf_periodc.postMacf:age36_45          0.06      0.04    -0.02     0.14 1.00     2914     2935
y_num:acf_perioda.preMacf:age46_55           0.19      0.04     0.11     0.28 1.00     1725     2580
y_num:acf_periodb.acf:age46_55               0.44      0.13     0.18     0.70 1.00     6134     2966
y_num:acf_periodc.postMacf:age46_55          0.09      0.04     0.01     0.18 1.00     2990     3023
y_num:acf_perioda.preMacf:age56_65           0.18      0.05     0.08     0.27 1.00     2110     2815
y_num:acf_periodb.acf:age56_65               0.39      0.13     0.13     0.64 1.00     7193     3277
y_num:acf_periodc.postMacf:age56_65          0.11      0.05     0.01     0.20 1.00     3256     2690
y_num:acf_perioda.preMacf:age65P             0.23      0.05     0.13     0.33 1.00     2429     3011
y_num:acf_periodb.acf:age65P                 0.43      0.13     0.18     0.68 1.00     5786     3216
y_num:acf_periodc.postMacf:age65P            0.11      0.05     0.01     0.20 1.00     3827     2943
y_num:acf_perioda.preMacf:sexM               0.02      0.04    -0.06     0.10 1.01     1197     2152
y_num:acf_periodb.acf:sexM                  -0.04      0.13    -0.30     0.22 1.00     6297     3212
y_num:acf_periodc.postMacf:sexM             -0.01      0.04    -0.08     0.06 1.00     2052     2719
y_num:acf_perioda.preMacf:age06_15:sexM      0.00      0.05    -0.10     0.10 1.00     1716     2568
y_num:acf_periodb.acf:age06_15:sexM          0.04      0.14    -0.23     0.32 1.00     6886     3066
y_num:acf_periodc.postMacf:age06_15:sexM     0.10      0.06    -0.02     0.21 1.00     3444     3117
y_num:acf_perioda.preMacf:age16_25:sexM     -0.00      0.05    -0.10     0.09 1.00     1425     2439
y_num:acf_periodb.acf:age16_25:sexM          0.06      0.14    -0.22     0.34 1.00     6452     3213
y_num:acf_periodc.postMacf:age16_25:sexM    -0.01      0.05    -0.11     0.09 1.00     2893     3235
y_num:acf_perioda.preMacf:age26_35:sexM     -0.01      0.05    -0.10     0.08 1.00     1444     2540
y_num:acf_periodb.acf:age26_35:sexM          0.05      0.14    -0.23     0.31 1.00     6098     3039
y_num:acf_periodc.postMacf:age26_35:sexM    -0.01      0.05    -0.10     0.09 1.00     2708     2917
y_num:acf_perioda.preMacf:age36_45:sexM     -0.01      0.05    -0.11     0.08 1.00     1513     2327
y_num:acf_periodb.acf:age36_45:sexM         -0.00      0.14    -0.26     0.26 1.00     6187     2910
y_num:acf_periodc.postMacf:age36_45:sexM    -0.00      0.05    -0.10     0.10 1.00     2945     3076
y_num:acf_perioda.preMacf:age46_55:sexM     -0.01      0.05    -0.11     0.09 1.00     1610     2520
y_num:acf_periodb.acf:age46_55:sexM         -0.00      0.14    -0.28     0.27 1.00     7308     2871
y_num:acf_periodc.postMacf:age46_55:sexM    -0.07      0.05    -0.17     0.04 1.00     2922     2775
y_num:acf_perioda.preMacf:age56_65:sexM      0.05      0.06    -0.06     0.16 1.00     1811     1970
y_num:acf_periodb.acf:age56_65:sexM          0.07      0.14    -0.20     0.35 1.00     6632     2582
y_num:acf_periodc.postMacf:age56_65:sexM     0.01      0.06    -0.09     0.12 1.00     2976     2962
y_num:acf_perioda.preMacf:age65P:sexM        0.00      0.06    -0.12     0.13 1.00     2189     2105
y_num:acf_periodb.acf:age65P:sexM            0.08      0.14    -0.21     0.36 1.00     6788     3003
y_num:acf_periodc.postMacf:age65P:sexM       0.01      0.06    -0.10     0.12 1.00     3548     2704

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape   221.49     75.06   115.49   404.66 1.00     2358     2635

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_age_sex)

pp_check(m_age_sex, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

Summarise posterior





#posterior draws, and summarise
age_sex_summary <- mdata_age_sex %>%
  select(year, year2, y_num, acf_period, age, sex) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year2, acf_period, age, sex) %>%
  mean_qi() %>%
  mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))

#create the counterfactual (no intervention), and summarise
age_sex_counterfact <- 
  tibble(year = mdata_age_sex$year,
         year2 = mdata_age_sex$year2,
         y_num = mdata_age_sex$y_num,
         age = mdata_age_sex$age,
         sex = mdata_age_sex$sex,
         acf_period = factor("a. pre-acf")) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year2, acf_period, age, sex) %>%
  mean_qi() %>%
  mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention")) %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) 



age_sex_summary %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) %>%
  ggplot() +
  geom_ribbon(aes(ymin=.epred.lower, ymax=.epred.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
  geom_ribbon(data = age_sex_counterfact %>% filter(year>=1956), 
              aes(ymin=.epred.lower, ymax=.epred.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
  geom_line(data = age_sex_counterfact %>% filter(year>=1956), 
              aes(y=.epred, x=year2, colour="Counterfactual")) +
  geom_line(aes(y=.epred, x=year2, group=acf_period,  colour=acf_period)) +
  geom_point(data = mdata_age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  mutate(sex = case_when(sex== "M" ~ "Male",
                         sex== "F" ~ "Female")) , aes(y=cases, x=year2, shape=acf_period), size=2) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  ggh4x::facet_grid2(age~sex, scales = "free_y", independent = "y") +
  theme_ggdist() +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
  scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="") +
  scale_shape_discrete(name="") +
  labs(
    x = "Year",
    y = "Case notifications (n)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA),
        title = element_text(size=14),
        axis.text = element_text(size=14),
        legend.text = element_text(size=12)) +
  guides(shape="none")
  
ggsave(here("figures/s7.png"), height=10)
Saving 7.29 x 10 in image

9.2 Summary of impact of intervention

(This all needs tidying up and checking - to do!)

  1. percentage increase in CNR, from 1956 to 1957 (i.e. immediate ACF effect)

nd <- mdata_age_sex %>%
  filter(year %in% c(1956:1957)) %>%
  select(acf_period, y_num, age, sex)


age_sex_impact_out <- 
  add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
         post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 
Warning: `cols` is now required when using `unnest()`.
ℹ Please use `cols = c(`a. pre-acf`, `b. acf`)`.
age_sex_impact_out %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()
`mutate_if()` ignored the following grouping variables:
  
f3a <- age_sex_impact_out %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1957) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  
  
  1. Change from pre-ACF period (1956), to first year post-ACF (1958)

nd <- mdata_age_sex %>%
  filter(year %in% c(1956,1958)) %>%
  select(acf_period, y_num, age, sex)

#Do it with calculating incidence, then sumamrising.
age_sex_impact2 <-add_epred_draws(m_age_sex,
                newdata=nd) %>%
  ungroup() %>%
  select(acf_period, .epred, age, sex) %>%
  pivot_wider(names_from = acf_period,
              values_from = .epred,
              values_fn = list) %>%
  unnest() %>%
  rename(pre_epred = 3,
        post_epred = 4) %>%
  mutate(acf_diff = post_epred-pre_epred,
         acf_rr = post_epred/pre_epred) %>%
  group_by(age, sex) %>%
  mean_qi(acf_diff, acf_rr) 
Warning: `cols` is now required when using `unnest()`.
ℹ Please use `cols = c(`a. pre-acf`, `c. post-acf`)`.
age_sex_impact2 %>%
  mutate_if(is.double, ~ scales::number(x = ., accuracy = 0.01, big.mark = ",")) %>%
  datatable()
`mutate_if()` ignored the following grouping variables:
f3b <- age_sex_impact2 %>%  
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(y=acf_rr, ymin=acf_rr.lower, ymax=acf_rr.upper, group=sex, 
                      x=age,
                      colour = sex),
                  position = position_dodge(width = 0.25)) +
  geom_hline(aes(yintercept=1), linetype=2) +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  labs(x="",
       y="Relative notifications (95% UI)\nACF (1958) vs. Before ACF (1956)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))
  1. Change in slope (i.e. difference in mean annual case notification rate pre-Intervention vs. post-intervention, by ward)

age_sex_impact3 <- mdata_age_sex %>%
  select(year, year2, y_num, acf_period, cases, age, sex) %>%
  filter(year!=1957) %>%
  add_epred_draws(m_age_sex) %>%
  group_by(year, age, sex, acf_period) %>%
  mean_qi(.epred) %>%
  ungroup() %>%
  mutate(n_years = length(year), .by=acf_period) %>%
  summarise(pct_change_epred_overall = (((last(.epred) - first(.epred))/first(.epred))),
            pct_change_lower_overall = (((last(.lower) - first(.lower))/first(.lower))),
            pct_change_upper_overall = (((last(.upper) - first(.upper))/first(.upper))),
    
            pct_change_epred_annual = (((last(.epred) - first(.epred))/first(.epred))/n_years),
            pct_change_lower_annual = (((last(.lower) - first(.lower))/first(.lower))/n_years),
            pct_change_upper_annual = (((last(.upper) - first(.upper))/first(.upper))/n_years),
            .by = c(acf_period, age, sex)) %>%
  distinct()
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
age_sex_impact3 %>%
  mutate_if(is.double, percent) %>%
  datatable()

f3c <- age_sex_impact3 %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
    geom_hline(aes(yintercept=0), linetype=2) +
    geom_pointrange(aes(y=pct_change_epred_annual, ymin=pct_change_lower_annual, ymax=pct_change_upper_annual, group=acf_period, 
                      x=age,
                      colour = acf_period), size=0.1) +
  scale_y_continuous(labels =percent) +
  facet_grid(.~sex) +
  coord_flip() +
  scale_colour_manual(values = c("#DE0D92", "#4D6CFA")) +
  labs(x="",
       y="Mean annual rate of change in case notification rate (95% UI)\n Before ACF (1950-1956) vs. after ACF (1958-1963)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

f3c

9.3 Compared to counterfactual


counterfact_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(year, age, sex, .draw, .epred_counterf = .epred)
Adding missing grouping variables: `year2`, `y_num`, `acf_period`, `.row`
  
#Calcuate incidence per draw, then summarise.
  post_change_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, age, sex, .draw, .epred) 
  
  #for the overall period
counterfact_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred)  %>%
      group_by(age, sex, .draw) %>%
      summarise(.epred_counterf = sum(.epred)) %>%
      mutate(year = "Overall (1958-1963)")
Adding missing grouping variables: `year`, `year2`, `y_num`, `acf_period`, `.row``summarise()` has grouped output by 'age', 'sex'. You can override using the `.groups` argument.
  
  #Calcuate incidence per draw, then summarise.
  post_change_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred) %>%
      group_by(.draw, age, sex) %>%
      summarise(.epred = sum(.epred)) 
Adding missing grouping variables: `year`, `year2`, `y_num`, `acf_period`, `.row``summarise()` has grouped output by '.draw', 'age'. You can override using the `.groups` argument.
  
  

left_join(counterfact_age_sex, post_change_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(year, age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
  datatable()
Joining with `by = join_by(year, age, sex, .draw)`
counter_post_overall_age_sex <-
  left_join(counterfact_overall_age_sex, post_change_overall_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 
Joining with `by = join_by(age, sex, .draw)`

age_sex_txt <- counter_post_overall_age_sex %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  transmute(year = as.character(year),
            sex = sex,
            age = age,
            cases_averted = glue::glue("{cases_averted}\n({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change}\n({pct_change.lower} to {pct_change.upper})"))


age_sex_txt %>% datatable()
NA
NA

f3d <- counter_post_overall_age_sex %>% 
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(x = age, y=cases_averted, ymin=cases_averted.lower, ymax=cases_averted.upper, colour=sex)) + 
  facet_grid(.~sex) +
  coord_flip() +
  scale_colour_manual(values = c("purple", "darkorange"), name="") +
  scale_y_continuous(labels = comma) +
  labs(x="",
       y="Number (95% UI) of TB cases averted (1958-1963)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "none")

f3d

Join together for Figure 2.


(f3a + f3b) / (f3c + f3d) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f3.png"), width = 12)
Saving 12 x 4.51 in image

mdata_age_sex

LS0tCnRpdGxlOiAiR2xhc2dvdyBUQiBBQ0YiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyAxLiBMaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKIyMjIyAxLjEgTGlicmFyaWVzCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMuCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobWFyZ2luYWxlZmZlY3RzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NpY28pCmxpYnJhcnkoZ2dkZW5zaXR5KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeSh1bml0cykKI2xpYnJhcnkoZ2dzbikKCmBgYAoKIyMjIyAxLjIgSGVscGVyIGZ1bmN0aW9ucwoKRnVuY3Rpb25zIHRoYXQgd2Ugd2lsbCB1c2UgdGhyb3VnaG91dCB0aGUgc2NyaXB0CgpgYGB7cn0KI2xhYmVsbGVyIGZvciB5ZWFycwp5ZWFyX2xhYmVscyA8LSBjKDE5NTA6MTk2MykKCiNUaGUgR2xhc2dvdyBtYXNzIG1pbnV0dXJlIGNoZXN0IFgtcmF5IGNhbXBhaWduIGhhcHBlbmVkIGJldHdlZW4gMTF0aCBNYXJjaCBhbmQgMTJ0aCBBcHJpbCAxOTU3CiNTZWdtZW50IGZvciBncmFwaHMgdG8gbWF0Y2ggQUNGIHBlcmlvZAphY2Zfc3RhcnQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wMy0xMSIpKQphY2ZfZW5kIDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDQtMTIiKSkKCgpgYGAKCkZ1bmN0aW9uIGZvciBjb3VudGVyZmFjdHVhbCBwbG90cwoKYGBge3J9CgoKcGxvdF9jb3VudGVyZmFjdHVhbCA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgb3V0Y29tZSwgZ3JvdXBpbmdfdmFyPU5VTEwsIHJlX2Zvcm11bGEsLi4uKXsKICAKICAjbGFiZWxsZXIgZm9yIHllYXJzCiAgeWVhcl9sYWJlbHMgPC0gYygxOTUwOjE5NjMpCgogICNUaGUgR2xhc2dvdyBtYXNzIG1pbnV0dXJlIGNoZXN0IFgtcmF5IGNhbXBhaWduIGhhcHBlbmVkIGJldHdlZW4gMTF0aCBNYXJjaCBhbmQgMTJ0aCBBcHJpbCAxOTU3CiAgI1NlZ21lbnQgZm9yIGdyYXBocyB0byBtYXRjaCBBQ0YgcGVyaW9kCiAgYWNmX3N0YXJ0IDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDMtMTEiKSkKICBhY2ZfZW5kIDwtIGRlY2ltYWxfZGF0ZSh5bWQoIjE5NTctMDQtMTIiKSkKCiAgc3VtbWFyeSA8LSB7e21vZGVsX2RhdGF9fSAlPiUKICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e291dGNvbWV9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBhZGRfZXByZWRfZHJhd3Moe3ttb2RlbH19LCByZV9mb3JtdWxhPXt7cmVfZm9ybXVsYX19KSAlPiUKICAgIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoKSAlPiUKICAgIG11dGF0ZSguZXByZWRfaW5jID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAgLmVwcmVkX2luYy51cHBlciA9IC5lcHJlZC51cHBlci97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICU+JQogICAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQoKCgogICNjcmVhdGUgdGhlIGNvdW50ZXJmYWN0dWFsIChubyBpbnRlcnZlbnRpb24pLCBhbmQgc3VtbWFyaXNlCiAgCiAgY291bnRlcmZhY3QgPC0KICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIHt7b3V0Y29tZX19KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSwgcmVfZm9ybXVsYT17e3JlX2Zvcm11bGF9fSkgJT4lCiAgICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtZWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgIC5lcHJlZF9pbmMubG93ZXIgPSAuZXByZWQubG93ZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAuZXByZWRfaW5jLnVwcGVyID0gLmVwcmVkLnVwcGVyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCkgJT4lCiAgICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQogIAoKCiAgI3Bsb3QgdGhlIGludGVydmVudGlvbiBlZmZlY3QKcCA8LSBzdW1tYXJ5ICU+JQogICAgZHJvcGxldmVscygpICU+JQogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBncm91cCA9IGFjZl9wZXJpb2QsIGZpbGw9YWNmX3BlcmlvZCksIGFscGhhPTAuNSkgKwogICAgZ2VvbV9yaWJib24oZGF0YSA9IGNvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkX2luYy5sb3dlciwgeW1heD0uZXByZWRfaW5jLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICAgIGdlb21fbGluZShkYXRhID0gY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkX2luYywgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogICAgZ2VvbV9wb2ludChkYXRhID0ge3ttb2RlbF9kYXRhfX0sIGFlcyh5PXt7b3V0Y29tZX19LCB4PXllYXIyLCBzaGFwZT1hY2ZfcGVyaW9kKSwgc2l6ZT0yKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgICB0aGVtZV9nZ2Rpc3QoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hLCBsaW1pdHMgPSBjKDAsTkEpKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9IiIsIG5hLnRyYW5zbGF0ZSA9IEYpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iIiwgbmEudHJhbnNsYXRlID0gRikgKwogICAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIiwgbmEudHJhbnNsYXRlID0gRikgKwogICAgbGFicygKICAgICAgeCA9ICJZZWFyIiwKICAgICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbiByYXRlIChwZXIgMTAwLDAwMCkiLAogICAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICAgKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemU9MTAsIGFuZ2xlID0gOTAsIGhqdXN0PTEsIHZqdXN0PTAuNSksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICAgZ3VpZGVzKHNoYXBlPSJub25lIikKCiAgICBmYWNldF92YXJzIDwtIHZhcnMoLi4uKQoKICBpZiAobGVuZ3RoKGZhY2V0X3ZhcnMpICE9IDApIHsKICAgIHAgPC0gcCArIGZhY2V0X3dyYXAoZmFjZXRfdmFycykKICB9CiAgcAoKfQoKYGBgCgpGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgIG1lYXN1cmVzIG9mIGNoYW5nZSBvdmVyIHRpbWUgKFJSLnBlYWssIFJSLmxldmVsLCBSUi5zbG9wZSkKCgpgYGB7cn0KCnN1bW1hcmlzZV9jaGFuZ2UgPC0gZnVuY3Rpb24obW9kZWxfZGF0YSwgbW9kZWwsIHBvcHVsYXRpb25fZGVub21pbmF0b3IsIGdyb3VwaW5nX3ZhciA9IE5VTEwsIHJlX2Zvcm11bGEgPSBOVUxMKSB7CiAgCiAgI2Z1bmN0aW9ucyBmb3IgY2FsY3VsYXRpbmcgUlIucGVhawogICNpLmUuIHJlbGF0aXZlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgaW4gMTk1NyB2cy4gY291bnRlcmZhY3R1YWwgdHJlbmQgZm9yIDE5NTcKICAKICBncm91cGluZ192YXIgPC0gZW5xdW8oZ3JvdXBpbmdfdmFyKQogIAogIGlmICghaXMubnVsbCh7e2dyb3VwaW5nX3Zhcn19KSkgewogICAgCiAgICAjbWFrZSB0aGUgcHJlZGljdGlvbiBtYXRyaXgsIGNvbmRpdGlvbmFsIG9uIHdoZXRoZXIgd2Ugd2FudCByYW5kb20gZWZmZWN0cyBpbmNsdWRlZCBvciBub3QuCiAgICBvdXQgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDgpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImIuIGFjZiIpCiAgICApCiAgfSBlbHNlIHsKICAgIAogICAgb3V0IDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0pICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDgpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImIuIGFjZiIpCiAgICApCiAgfQogIAogIHBlYWtfZHJhd3MgPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXQsCiAgICAgICAgICAgICAgICAgIG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IHt7cmVfZm9ybXVsYX19KSAlPiUKICAgIG11dGF0ZShlcHJlZF9jbnIgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3QoZXByZWRfY25yKS9maXJzdChlcHJlZF9jbnIpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnBlYWsiKQogIAogIHBlYWtfc3VtbWFyeSA8LSBwZWFrX2RyYXdzICU+JQogICAgZ3JvdXBfYnkoISFncm91cGluZ192YXIpICU+JQogICAgbWVhbl9xaShlc3RpbWF0ZSkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5wZWFrIikKICAKICAKICAjZnVuY3Rpb25zIGZvciBjYWxjdWxhdGluZyBSUi5zdGVwCiAgI2kuZS4gcmVsYXRpdmUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSBpbiAxOTU4IHZzLiBjb3VudGVyZmFjdHVhbCB0cmVuZCBmb3IgMTk1OAogIAogICAgaWYgKCFpcy5udWxsKHt7Z3JvdXBpbmdfdmFyfX0pKSB7CiAgICBvdXQyIDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0sICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSA9PSA5KSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJjLiBwb3N0LWFjZiIpCiAgICApCiAgfSBlbHNlIHsKICAgIAogICAgb3V0MiA8LSBjcm9zc2luZyh7e21vZGVsX2RhdGF9fSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Qoe3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHlfbnVtKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSA9PSA5KSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJjLiBwb3N0LWFjZiIpCiAgICApCiAgfQogIAogICAgbGV2ZWxfZHJhd3MgPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXQyLAogICAgICAgICAgICAgICAgICBvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICBhcnJhbmdlKHlfbnVtLCAuZHJhdykgJT4lCiAgICBtdXRhdGUoZXByZWRfY25yID0gLmVwcmVkL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICAgIGdyb3VwX2J5KC5kcmF3LCAhIWdyb3VwaW5nX3ZhcikgJT4lCiAgICBzdW1tYXJpc2UoZXN0aW1hdGUgPSBsYXN0KGVwcmVkX2NucikvZmlyc3QoZXByZWRfY25yKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5sZXZlbCIpCiAgCiAgbGV2ZWxfc3VtbWFyeSA8LSBsZXZlbF9kcmF3cyAlPiUKICAgIGdyb3VwX2J5KCEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgIG1lYW5fcWkoZXN0aW1hdGUpICU+JQogICAgbXV0YXRlKG1lYXN1cmUgPSAiUlIubGV2ZWwiKQogICAgCiAgICAKICAjZnVuY3Rpb25zIGZvciBjYWxjdWxhdGluZyBSUi5zbG9wZQogICNpLmUuIHJlbGF0aXZlIGNoYW5nZSBpbiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIGluIDE5NTgtMTk2MyB2cy4gY291bnRlcmZhY3R1YWwgdHJlbmQgZm9yIDE5NTktMTk2MwogIAogICAgaWYgKCFpcy5udWxsKHt7Z3JvdXBpbmdfdmFyfX0pKSB7CiAgICBvdXQzIDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0sICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSAlaW4lIGMoOSwxNCkpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikKICAgICkKICB9IGVsc2UgewogICAgCiAgICBvdXQzIDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0pICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtICVpbiUgYyg5LDE0KSksCiAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYy4gcG9zdC1hY2YiKQogICAgKQogIH0KICAKICAgIHNsb3BlX2RyYXdzIDwtIGFkZF9lcHJlZF9kcmF3cyhuZXdkYXRhID0gb3V0MywKICAgICAgICAgICAgICAgICAgb2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0ge3tyZV9mb3JtdWxhfX0pICU+JQogICAgICAgIGFycmFuZ2UoeV9udW0pICU+JQogICAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgICBtdXRhdGUoZXByZWRfY25yID0gLmVwcmVkL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICAgICAgICBncm91cF9ieSguZHJhdywgYWNmX3BlcmlvZCwgISFncm91cGluZ192YXIpICU+JQogICAgICAgIHN1bW1hcmlzZShzbG9wZSA9IChsYXN0KGVwcmVkX2NucikgLSBmaXJzdChlcHJlZF9jbnIpKSAvIChsYXN0KHlfbnVtKS1maXJzdCh5X251bSkpKSAlPiUKICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgZ3JvdXBfYnkoLmRyYXcsICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgICBzdW1tYXJpc2UoZXN0aW1hdGUgPSBsYXN0KHNsb3BlKS9maXJzdChzbG9wZSkpICU+JQogICAgICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnNsb3BlIikKICAKICBzbG9wZV9zdW1tYXJ5IDwtIHNsb3BlX2RyYXdzICU+JQogICAgIGdyb3VwX2J5KCEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgbWVkaWFuX3FpKGVzdGltYXRlKSAlPiUKICAgICAgbXV0YXRlKG1lYXN1cmUgPSAiUlIuc2xvcGUiKQogICAgCiAgI2dhdGhlciBhbGwgdGhlIHJlc3VsdHMgaW50byBhIG5hbWVkIGxpc3QKICAgIGxzdChwZWFrX2RyYXdzPXBlYWtfZHJhd3MsIHBlYWtfc3VtbWFyeT1wZWFrX3N1bW1hcnksIAogICAgICAgIGxldmVsX2RyYXdzPWxldmVsX2RyYXdzLCBsZXZlbF9zdW1tYXJ5PWxldmVsX3N1bW1hcnksIAogICAgICAgIHNsb3BlX2RyYXdzPXNsb3BlX2RyYXdzLCBzbG9wZV9zdW1tYXJ5PXNsb3BlX3N1bW1hcnkpCiAgCn0KCmBgYAoKCkZ1bmN0aW9uIGZvciBjYWxjdWxhdGluZyBkaWZmZXJlbmNlIGZyb20gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKY2FsY3VsYXRlX2NvdW50ZXJmYWN0dWFsIDwtIGZ1bmN0aW9uKG1vZGVsX2RhdGEsIG1vZGVsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yLCBncm91cGluZ192YXI9TlVMTCwgcmVfZm9ybXVsYT1OQSl7CiAgCiAgI2VmZmVjdCB2cy4gY291bnRlcmZhY3R1YWwKICBjb3VudGVyZmFjdCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSwKICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kKSAlPiUKICAgICAgbXV0YXRlKC5lcHJlZF9pbmNfY291bnRlcmYgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLCAuZXByZWRfY291bnRlcmY9LmVwcmVkKSAgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgLmRyYXcsIC5lcHJlZF9jb3VudGVyZiwgLmVwcmVkX2luY19jb3VudGVyZiwge3tncm91cGluZ192YXJ9fSkKICAKICAjQ2FsY3VhdGUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2UgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpLAogICAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IHt7cmVfZm9ybXVsYX19KSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpICU+JQogICAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCAuZHJhdywgLmVwcmVkLCAuZXByZWRfaW5jLCB7e2dyb3VwaW5nX3Zhcn19KSAKICAKICAjZm9yIHRoZSBvdmVyYWxsIHBlcmlvZAogICAgY291bnRlcmZhY3Rfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSwKICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCAuZHJhdywgLmVwcmVkLCB7e2dyb3VwaW5nX3Zhcn19KSAgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZF9jb3VudGVyZiA9IHN1bSguZXByZWQpKSAKICAKICAjQ2FsY3VhdGUgY2FzZSBub3RpZmljYXRpb24gcmF0ZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2Vfb3ZlcmFsbCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCksCiAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0ge3tyZV9mb3JtdWxhfX0pICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZCA9IHN1bSguZXByZWQpKSAKICAKICAKY291bnRlcl9wb3N0IDwtCiAgbGVmdF9qb2luKGNvdW50ZXJmYWN0LCBwb3N0X2NoYW5nZSkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZiwKICAgICAgICAgICBkaWZmX2luYzEwMGsgPSAuZXByZWRfaW5jIC0gLmVwcmVkX2luY19jb3VudGVyZiwKICAgICAgICAgICBycl9pbmMxMDBrID0gLmVwcmVkX2luYy8uZXByZWRfaW5jX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHllYXIsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlLCBkaWZmX2luYzEwMGssIHJyX2luYzEwMGspICU+JQogICAgdW5ncm91cCgpCgpjb3VudGVyX3Bvc3Rfb3ZlcmFsbCA8LQogIGxlZnRfam9pbihjb3VudGVyZmFjdF9vdmVyYWxsLCBwb3N0X2NoYW5nZV9vdmVyYWxsKSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKQoKbHN0KGNvdW50ZXJfcG9zdCwgY291bnRlcl9wb3N0X292ZXJhbGwpCgp9CgoKYGBgCgpGdW5jdGlvbiBmb3IgdGlkeWluZyB1cCBjb3VudGVyZmFjdHVhbHMgKG1vc3RseSBmb3IgbWFraW5nIG5pY2UgdGFibGVzKQoKYGBge3J9Cgp0aWR5X2NvdW50ZXJmYWN0dWFscyA8LSBmdW5jdGlvbihkYXRhKXsKICBkYXRhICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsIGRpZmZfaW5jMTAwazpkaWZmX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocnJfaW5jMTAwazpycl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMDEpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZSh5ZWFyID0gYXMuY2hhcmFjdGVyKHllYXIpLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9ICh7Y2FzZXNfYXZlcnRlZC5sb3dlcn0gdG8ge2Nhc2VzX2F2ZXJ0ZWQudXBwZXJ9KSIpLAogICAgICAgICAgICBwY3RfY2hhbmdlID0gZ2x1ZTo6Z2x1ZSgie3BjdF9jaGFuZ2V9ICh7cGN0X2NoYW5nZS5sb3dlcn0gdG8ge3BjdF9jaGFuZ2UudXBwZXJ9KSIpLAogICAgICAgICAgICBkaWZmX2luYyA9IGdsdWU6OmdsdWUoIntkaWZmX2luYzEwMGt9ICh7ZGlmZl9pbmMxMDBrLmxvd2VyfSB0byB7ZGlmZl9pbmMxMDBrLnVwcGVyfSkiKSwKICAgICAgICAgICAgcnJfaW5jID0gZ2x1ZTo6Z2x1ZSgie3JyX2luYzEwMGt9ICh7cnJfaW5jMTAway5sb3dlcn0gdG8ge3JyX2luYzEwMGsudXBwZXJ9KSIpKQp9CgoKdGlkeV9jb3VudGVyZmFjdHVhbHNfb3ZlcmFsbCA8LSBmdW5jdGlvbihkYXRhKXsKICBkYXRhICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIGNhc2VzX2F2ZXJ0ZWQgPSBnbHVlOjpnbHVlKCJ7Y2FzZXNfYXZlcnRlZH0gKHtjYXNlc19hdmVydGVkLmxvd2VyfSB0byB7Y2FzZXNfYXZlcnRlZC51cHBlcn0pIiksCiAgICAgICAgICAgIHBjdF9jaGFuZ2UgPSBnbHVlOjpnbHVlKCJ7cGN0X2NoYW5nZX0gKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIikpCn0KCmBgYAoKCgojIyMgMi4gRGF0YQoKSW1wb3J0IGRhdGFzZXRzIGZvciBhbmFseXNpcwoKIyMjIyAyLjEgU2hhcGVmaWxlcwoKTWFrZSBhIG1hcCBvZiBHbGFzZ293IHdhcmRzCgpgYGB7cn0KCmdsYXNnb3dfd2FyZHNfMTk1MSA8LSBzdF9yZWFkKGhlcmUoIm1hcHBpbmcvZ2xhc2dvd193YXJkc18xOTUxLmdlb2pzb24iKSkKCmBgYAoKYGBge3J9CgojcmVhZCBpbiBTY290bGFuZCBib3VuZGFyeQpzY290bGFuZCA8LSBzdF9yZWFkKGhlcmUoIm1hcHBpbmcvU2NvdGxhbmRfYm91bmRhcnkvU2NvdGxhbmQgYm91bmRhcnkuc2hwIikpCgojbWFrZSBhIGJvdW5kaW5nIGJveCBmb3IgR2xhc2dvdwpiYm94IDwtIHN0X2Jib3goZ2xhc2dvd193YXJkc18xOTUxKSB8PiBzdF9hc19zZmMoKQoKI3Bsb3Qgc2NvdGxhbmQgd2l0aCBhIGJvdW5kaW5nIGJveCBhcm91bmQgdGhlIENpdHkgb2YgR2xhc2dvdwpzY290bGFuZF93aXRoX2Jib3ggPC0gZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHNjb3RsYW5kLCBmaWxsPSJhbnRpcXVld2hpdGUiKSArCiAgZ2VvbV9zZihkYXRhID0gYmJveCwgY29sb3VyID0gIiNDNjBDMzAiLCBmaWxsPSJhbnRpcXVld2hpdGUiKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEsIGxpbmV3aWR0aCA9IDAuNSksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFQUY3RkEiLCBzaXplID0gMC4zKSkKCiNwbG90IHRoZSB3YXJkcwojbm90ZSB3ZSB0aWR5IHVwIHNvbWUgbmFtZXMgdG8gZml0IG9uIG1hcApnbGFzZ293X3dhcmRfbWFwIDwtIGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKICBtdXRhdGUod2FyZCA9IGNhc2Vfd2hlbih3YXJkPT0iU2hldHRsZXN0b24gYW5kIFRvbGxjcm9zcyIgfiAiU2hldHRsZXN0b24gYW5kXG5Ub2xsY3Jvc3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJQYXJ0aWNrIChXZXN0KSIgfiAiUGFydGlja1xuKFdlc3QpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iUGFydGljayAoRWFzdCkiIH4gIlBhcnRpY2tcbihFYXN0KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09Ik5vcnRoIEtlbHZpbiIgfiAiTm9ydGhcbktlbHZpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09Iktpbm5pbmcgUGFyayIgfiAiS2lubmluZ1xuUGFyayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IHdhcmQpKSAlPiUKICAKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihhZXMoZmlsbD1kaXZpc2lvbikpICsKICBnZW9tX3NmX2xhYmVsKGFlcyhsYWJlbCA9IHdhcmQpLCBzaXplPTMsIGZpbGw9TkEsIGxhYmVsLnNpemUgPSBOQSwgY29sb3VyPSJibGFjayIpICsKICAjc2NhbGVfY29sb3VyX2lkZW50aXR5KCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWU9IkNpdHkgb2YgR2xhc2dvdyBEaXZpc2lvbiIpICsKICB0aGVtZV9ncmV5KCkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IiIsCiAgICAgICBmaWxsPSJEaXZpc2lvbiIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEsIGxpbmV3aWR0aCA9IDAuNSksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImFudGlxdWV3aGl0ZSIsIHNpemUgPSAwLjMpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JleTc4IikpICsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIiwgdGl0bGUuaGp1c3QgPSAwLjUsIHRpdGxlLnRoZW1lID0gZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiKSkpCgojYWRkIHRoZSBtYXAgb2Ygc2NvdGxhbmQgYXMgYW4gaW5zZXQKZ2xhc2dvd193YXJkX21hcCArIGluc2V0X2VsZW1lbnQoc2NvdGxhbmRfd2l0aF9iYm94LCAwLjc1LCAwLCAxLCAwLjQpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMS5wbmciKSwgaGVpZ2h0PTEwLCB3aWR0aCA9IDEyKQoKCmBgYAoKQ2FsY3VsYXRlIGFyZWFzIHBlciBnZW9ncmFwaGljYWwgdW5pdAoKYGBge3J9CnNmX3VzZV9zMihGQUxTRSkgI2h0dHBzOi8vZ2l0aHViLmNvbS9yLXNwYXRpYWwvc2YvaXNzdWVzLzE3NjIKCmdsYXNnb3dfd2FyZHNfMTk1MSA8LSBnbGFzZ293X3dhcmRzXzE5NTEgJT4lCiAgbXV0YXRlKGFyZWEgPSBzdF9hcmVhKGdsYXNnb3dfd2FyZHNfMTk1MSkpCgoKZ2xhc2dvd193YXJkc18xOTUxJGFyZWFfa20gPC0gdW5pdHM6OnNldF91bml0cyhnbGFzZ293X3dhcmRzXzE5NTEkYXJlYSwga21eMikKCgpgYGAKCgpNYWtlIGRpdmlzaW9uIHNoYXBlIGZpbGVzLCBhbmQgY2FsY3VsYXRlIGFyZWEKKHN0b3BwZWQgd29ya2luZywgbmVlZCB0byBmaXghKQoKYGBge3J9CgojIGdsYXNnb3dfZGl2aXNpb25zXzE5NTEgPC0gZ2xhc2dvd193YXJkc18xOTUxICU+JQojICAgZ3JvdXBfYnkoZGl2aXNpb24pICU+JSAKIyAgIHN1bW1hcml6ZShnZW9tZXRyeSA9IHN0X3VuaW9uKGdlb21ldHJ5KSkgJT4lCiMgICBubmdlbzo6c3RfcmVtb3ZlX2hvbGVzKCkgJT4lCiMgICBtdXRhdGUoYXJlYSA9IHN0X2FyZWEoZ2xhc2dvd19kaXZpc2lvbnNfMTk1MSkpCiMgCiMgZ2xhc2dvd19kaXZpc2lvbnNfMTk1MSRhcmVhX2ttIDwtIHVuaXRzOjpzZXRfdW5pdHMoZ2xhc2dvd19kaXZpc2lvbnNfMTk1MSRhcmVhLCBrbV4yKQoKCmBgYAoKCiMjIyAzLiBEZW5vbWluYXRvcnMKCkxvYWQgaW4gdGhlIGRhdGFzZXRzIGZvciBkZW5vbm9taWF0b3JzLCBhbmQgY2hlY2sgZm9yIGNvbnNpc3RlbmN5LgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgPC0gcmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAib3ZlcmFsbF9wb3B1bGF0aW9uIikKCm92ZXJhbGxfcG9wcyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApvdmVyYWxsX3BvcHMgPC0gb3ZlcmFsbF9wb3BzICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKYGBgCgpOb3RlLCB3ZSBoYXZlIHRocmVlIHBvcHVsYXRpb24gZXN0aW1hdGVzOgoKMS4gUG9wdWxhdGlvbiB3aXRob3V0IGluc3RpdHV0aW9uYWxpc2VkIHBlb3BsZSBvciBwZW9wbGUgaW4gc2hpcHBpbmcKMi4gUG9wdWxhdGlvbiBpbiBpbnN0aXR1dGlvbnMKMy4gUG9wdWxhdGlvbiBpbiBzaGlwcGluZwoKKFBvcHVsYXRpb24gaW4gc2hpcHBpbmcgaXMgZXN0aW1hdGVkIGZyb20gdGhlIDE5NTEgY2Vuc3VzLCBzbyBpcyB0aGUgc2FtZSBmb3IgbW9zdCB5ZWFycykKCiMjIyMgMy4xIE92ZXJhbGwgcG9wdWxhdGlvbgoKRmlyc3QsIHBsb3QgdGhlIHRvdGFsIHBvcHVsYXRpb24KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiksIGFscGhhPTAuNSwgY29sb3VyID0gIm1lZGl1bXNlYWdyZWVuIiwgZmlsbD0ibWVkaXVtc2VhZ3JlZW4iKSArCiAgZ2VvbV9wb2ludChhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyKSwgY29sb3VyID0gIm1lZGl1bXNlYWdyZWVuIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiB0b3RhbCBwb3B1bGF0aW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKQoKCmBgYAoKTm93IHRoZSBwb3B1bGF0aW9uIGV4Y2x1ZGluZyBpbnN0aXR1dGlvbmFsaXNlZCBhbmQgc2hpcHBpbmcgcG9wdWxhdGlvbgoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB4PXllYXIyKSwgYWxwaGE9MC41LCBjb2xvdXIgPSAicHVycGxlIiwgZmlsbD0icHVycGxlIikgKwogIGdlb21fcG9pbnQoYWVzKHk9cG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgeD15ZWFyMiksIGNvbG91ciA9ICJwdXJwbGUiKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IHBvcHVsYXRpb24gZXhjbHVkaW5nIGluc3RpdHV0aW9uYWxpc2VkIGFuZCBzaGlwcGluZyIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkKCgpgYGAKCiMjIyMgMy4yIFBvcHVsYXRpb24gYnkgV2FyZAoKVGhlcmUgYXJlIDUgRGl2aXNpb25zIGNvbnRhaW5pbmcgMzcgV2FyZHMgaW4gdGhlIEdsYXNnb3cgQ29ycG9yYXRpb24sIHdpdGggY29uc2lzdGVudCBib3VuZGFyaWVzIG92ZXIgdGltZS4KCmBgYHtyfQojbG9vay11cCB0YWJsZSBmb3IgZGl2aXNpb25zIGFuZCB3YXJkcwp3YXJkX2xvb2t1cCA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJkaXZpc2lvbnNfd2FyZHMiKQoKCndhcmRfcG9wcyA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJ3YXJkX3BvcHVsYXRpb24iKQoKd2FyZF9wb3BzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CndhcmRfcG9wcyA8LSB3YXJkX3BvcHMgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgojR2V0IHRoZSBEaXZpc2lvbiBwb3B1bGF0aW9uCmRpdmlzaW9uX3BvcHMgPC0gd2FyZF9wb3BzICU+JQogIGdyb3VwX2J5KGRpdmlzaW9uLCB5ZWFyKSAlPiUKICBzdW1tYXJpc2UocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCA9IHN1bShwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBpbnN0aXR1dGlvbnMgPSBzdW0oaW5zdGl0dXRpb25zLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBzaGlwcGluZyA9IHN1bShzaGlwcGluZywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgdG90YWxfcG9wdWxhdGlvbiA9IHN1bSh0b3RhbF9wb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpKQoKZGl2aXNpb25fcG9wcyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKClBsb3QgdGhlIG92ZXJhbGwgcG9wdWxhdGlvbiBieSBEaXZpc2lvbiBhbmQgV2FyZAoKYGBge3J9CgpkaXZpc2lvbl9wb3BzICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbiwgZmlsbD1kaXZpc2lvbiksIGFscGhhPTAuOCkgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uKSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIiwgbmFtZSA9ICIiKSArCiAgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lID0gIiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogdG90YWwgcG9wdWxhdGlvbiBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCmBgYAoKYGBge3J9Cgp3YXJkX3BvcHMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyLCBjb2xvdXI9ZGl2aXNpb24sIGZpbGw9ZGl2aXNpb24pLCBhbHBoYT0wLjgpICsKICBnZW9tX3BvaW50KGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbikpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIGZhY2V0X3dyYXAod2FyZH4uLCBuY29sPTYpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJEaXZpc2lvbiIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiRGl2aXNpb24iKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ2l0eTogdG90YWwgcG9wdWxhdGlvbiBieSBXYXJkIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MyIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJQb3B1bGF0aW9uIiwKICAgIGNhcHRpb24gPSAiTWlkLXllYXIgZXN0aW1hdGVzXG5NYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KSIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMi5wbmciKSwgaGVpZ2h0PTEwLCB3aWR0aD0xMikKCmBgYAoKQXBwcm94aW1hdGVseSwgaG93IG1hbnkgcGVyc29uLXllYXJzIG9mIGZvbGxvdy11cCBkbyB3ZSBoYXZlPwoKYGBge3J9CgpvdmVyYWxsX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIHN1bW1hcmlzZShhY3Jvc3MoeWVhciwgbGVuZ3RoLCAubmFtZXMgPSAieWVhcnMiKSwKICAgICAgICAgICAgYWNyb3NzKGMocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbiksIHN1bSkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuZG91YmxlKSwgY29tbWEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKQ2hhbmdlIGluIHBvcHVsYXRpb24gYnkgd2FyZAoKYGBge3J9Cgp3YXJkX3BvcHMgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgc3VtbWFyaXNlKHBjdF9jaGFuZ2VfcG9wID0gKGxhc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkgLSBmaXJzdChwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSkvZmlyc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpICU+JQogIG11dGF0ZShwY3RfY2hhbmdlX3BvcCA9IHBlcmNlbnQocGN0X2NoYW5nZV9wb3ApKSAlPiUKICBhcnJhbmdlKHBjdF9jaGFuZ2VfcG9wKSAlPiUKICBkYXRhdGFibGUoKQogIAoKCmBgYAoKT3V0cHV0IHBvcHVsYXRpb24gZGVuc2l0eSBieSB3YXJkIGFuZCBkaXZpc29uIGZvciByZWdyZXNzaW9uIG1vZGVsbGluZwoKV2FyZHMgZmlyc3QKCihzdG9wcGVkIHdvcmtpbmcsIG5lZWQgdG8gZml4KQoKYGBge3J9CgojIHdhcmRfY292YXJpYXRlcyA8LSAgZ2xhc2dvd193YXJkc18xOTUxICU+JQojICAgbGVmdF9qb2luKHdhcmRfcG9wcykgJT4lCiMgICBtdXRhdGUocGVvcGxlX3Blcl9rbV9zcSA9IGFzLmRvdWJsZShwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwL2FyZWFfa20pKQojIAojICNwbG90IGl0IG91dAojIAojIHdhcmRfY292YXJpYXRlcyAlPiUKIyAgIGdncGxvdCgpICsKIyAgIGdlb21fc2YoYWVzKGZpbGw9cGVvcGxlX3Blcl9rbV9zcSkpICsgCiMgICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbD03KSArCiMgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249IkEiKSArCiMgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKIyAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQojIAojIGdnc2F2ZShoZXJlKCJmaWd1cmVzL3dhcmRfcG9wX2RlbnNpdHkucG5nIiksIHdpZHRoPTEwKQojIAojIHdyaXRlX3Jkcyh3YXJkX2NvdmFyaWF0ZXMsIGhlcmUoInBvcHVsYXRpb25zL3dhcmRfY292YXJpYXRlcy5yZHMiKSkKCgpgYGAKCk5vdyBkaXZpc2lvbnMgZmlyc3QKCgooc3RvcHBlZCB3b3JraW5nLCBuZWVkIHRvIGZpeCkKCmBgYHtyfQoKIyBkaXZpc2lvbl9jb3ZhcmlhdGVzIDwtICBnbGFzZ293X2RpdmlzaW9uc18xOTUxICU+JQojICAgbGVmdF9qb2luKGRpdmlzaW9uX3BvcHMpICU+JQojICAgbXV0YXRlKHBlb3BsZV9wZXJfa21fc3EgPSBhcy5kb3VibGUodG90YWxfcG9wdWxhdGlvbi9hcmVhX2ttKSkKIyAKIyAjcGxvdCBpdCBvdXQKIyAKIyBkaXZpc2lvbl9jb3ZhcmlhdGVzICU+JQojICAgZ2dwbG90KCkgKwojICAgZ2VvbV9zZihhZXMoZmlsbD1wZW9wbGVfcGVyX2ttX3NxKSkgKyAKIyAgIGdlb21fc2ZfbGFiZWwoYWVzKGxhYmVsID0gZGl2aXNpb24pLCBzaXplPTMsIGZpbGw9TkEsIGxhYmVsLnNpemUgPSBOQSwgY29sb3VyPSJibGFjayIsIGZhbWlseSA9ICJTZWdvZSBVSSIpICsKIyAgIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sPTcpICsKIyAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbj0iRyIpICsKIyAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAojICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MSkpCiMgCiMgZ2dzYXZlKGhlcmUoImZpZ3VyZXMvZGl2aXNpb25fcG9wX2RlbnNpdHkucG5nIiksIHdpZHRoPTEwKQojIAojIHdyaXRlX3JkcyhkaXZpc2lvbl9jb3ZhcmlhdGVzLCBoZXJlKCJwb3B1bGF0aW9ucy9kaXZpc2lvbl9jb3ZhcmlhdGVzLnJkcyIpKQoKYGBgCgoKIyMjIyAzLjMgUG9wdWxhdGlvbiBieSBhZ2UgYW5kIHNleAoKYGBge3J9CgphZ2Vfc2V4IDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImFnZV9zZXhfcG9wdWxhdGlvbiIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhtYWxlLCBmZW1hbGUpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJzZXgiKQoKI2NvbGxhcHNlIGRvd24gdG8gc21hbGxlciBhZ2UgZ3JvdXBzIHRvIGJlIG1hbmFnZWFibGUKYWdlX3NleCA8LSBhZ2Vfc2V4ICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZSA9PSAiMCB0byA0IiB+ICIwMCB0byAwNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPT0gIjUgdG8gOSIgfiAiMDUgdG8gMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIxMCB0byAxNCIgfiAiMDUgdG8gMTQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIxNSB0byAxOSIgfiAiMTUgdG8gMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIyMCB0byAyNCIgfiAiMTUgdG8gMjQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIyNSB0byAyOSIgfiAiMjUgdG8gMzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIzMCB0byAzNCIgfiAiMjUgdG8gMzQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICIzNSB0byAzOSIgfiAiMzUgdG8gNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI0MCB0byA0NCIgfiAiMzUgdG8gNDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI0NSB0byA0OSIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1MCB0byA1NCIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1NSB0byA1OSIgfiAiNDUgdG8gNTkiLAogICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICI2MCAmIHVwIikpICU+JQogIGdyb3VwX2J5KHllYXIsIGFnZSwgc2V4KSAlPiUKICBtdXRhdGUodmFsdWUgPSBzdW0odmFsdWUpKSAlPiUKICB1bmdyb3VwKCkKCgoKbV9hZ2Vfc2V4IDwtIGxtKHZhbHVlIH4gc3BsaW5lczo6bnMoeWVhciwga25vdHMgPSAzKSphZ2Uqc2V4LCBkYXRhID0gYWdlX3NleCkKCnN1bW1hcnkobV9hZ2Vfc2V4KQoKYWdlX2xldmVscyA8LSBhZ2Vfc2V4ICU+JSBzZWxlY3QoYWdlKSAlPiUgZGlzdGluY3QoKSAlPiUgcHVsbCgpIAoKYWdlX3NleF9uZCA8LSAKICBjcm9zc2luZygKICAgIGFnZT1hZ2VfbGV2ZWxzLAogICAgc2V4PWMoIm1hbGUiLCAiZmVtYWxlIiksCiAgICB5ZWFyID0gMTk1MDoxOTYzCiAgKQoKcHJlZF9wb3BzIDwtIGFnZV9zZXhfbmQgJT4lIG1vZGVscjo6YWRkX3ByZWRpY3Rpb25zKG1fYWdlX3NleCkKCnByZWRfcG9wcyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wcmVkLCBjb2xvdXI9YWdlKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQoc2V4fi4pICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoMCwgMTI1MDAwKSkKCiNIb3cgd2VsbCBkbyB0aGV5IG1hdGNoIHVwIHdpdGggb3VyIG92ZXJhbGwgcG9wdWxhdGlvbnM/CnByZWRfcG9wcyAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2Uoc3VtX3ByZWRfcG9wID0gc3VtKHByZWQpKSAlPiUKICByaWdodF9qb2luKG92ZXJhbGxfcG9wcykgJT4lCiAgc2VsZWN0KHllYXIsIHN1bV9wcmVkX3BvcCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHN1bV9wcmVkX3BvcCwgcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgdG90YWxfcG9wdWxhdGlvbikpICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXZhbHVlLCBjb2xvdXI9bmFtZSkpICsKICBnZW9tX3BvaW50KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSwgbGltaXRzID0gYyg4MDAwMDAsIDEyNTAwMDApKQoKcHJlZF9wb3BzICU+JQogIGdyb3VwX2J5KHllYXIsIHNleCkgJT4lCiAgc3VtbWFyaXNlKHN1bSA9IHN1bShwcmVkKSkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHNleF9yYXRpbyA9IGZpcnN0KHN1bSkvbGFzdChzdW0pKQpgYGAKCgpXaGF0IHBlcmNlbnRhZ2Ugb2YgYWR1bHRzICgxNSsgcGFydGljaXBhdGVkIGluIHRoZSBpbnRlcnZlbnRpb24gaW4gMTk1Nyk/CgpgYGB7cn0KCnByZWRfcG9wcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKHllYXI9PTE5NTcpICU+JQogIGZpbHRlcihhZ2UgIT0gIjAwIHRvIDA0IiwKICAgICAgICAgYWdlICE9ICIwNSB0byAxNCIpICU+JQogIHN1bW1hcmlzZSh0b3RhbF9wb3AgPSBzdW0ocHJlZCkpICU+JQogIG11dGF0ZShjeHJfc2NyZWVuZWQgPSA2MjIzNDkpICU+JQogIG11dGF0ZShwY3RfcG9wX2N4cl9zY3JlZW5lZCA9IHBlcmNlbnQoY3hyX3NjcmVlbmVkL3RvdGFsX3BvcCkpCgpwcmVkX3BvcHMgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcih5ZWFyPT0xOTU3KSAlPiUKICBmaWx0ZXIoYWdlICE9ICIwMCB0byAwNCIsCiAgICAgICAgIGFnZSAhPSAiMDUgdG8gMTQiKSAlPiUKICBzdW1tYXJpc2UodG90YWxfcG9wID0gc3VtKHByZWQpLCAuYnk9c2V4KSAlPiUKICBtdXRhdGUoY3hyX3NjcmVlbmVkID0gYygzNDA0NzQsIDI4MTg3NSkpICU+JQogIG11dGF0ZShwY3RfcG9wX2N4cl9zY3JlZW5lZCA9IHBlcmNlbnQoY3hyX3NjcmVlbmVkL3RvdGFsX3BvcCkpCgoKYGBgCgoKUG9wdWxhdGlvbiBweXJhbWlkcwoKYGBge3J9CgpsYWJlbF9hYnMgPC0gZnVuY3Rpb24oeCkgewogIGNvbW1hKGFicyh4KSkKfQoKCnByZWRfcG9wcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHllYXJfcG9wID0gc3VtKHByZWQpLAogICAgICAgICBhZ2Vfc2V4X3BjdCA9IHBlcmNlbnQocHJlZC95ZWFyX3BvcCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJtYWxlIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ImZlbWFsZSIgfiAiRmVtYWxlIikpICU+JQogIGdncGxvdCgKICAgIGFlcyh4ID0gYWdlLCBmaWxsID0gc2V4LCAKICAgICAgICB5ID0gaWZlbHNlKHRlc3QgPSBzZXggPT0gIkZlbWFsZSIseWVzID0gLXByZWQsIG5vID0gcHJlZCkpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGFnZV9zZXhfcGN0KSwKICAgICAgICAgICAgcG9zaXRpb249IHBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIGNvbG91cj0id2hpdGUiLCBzaXplPTIuNSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sPTcpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9hYnMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJtZWRpdW1zZWFncmVlbiIsICJwdXJwbGUiKSwgbmFtZT0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3QgPSAxLCB2anVzdD0wLjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IiIsIHk9IiIpIAoKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MzLnBuZyIpLCB3aWR0aD0xMCkKCgpgYGAKCk5vdCBwZXJmZWN0LCBidXQgcmVzb25hYmx5IGdvb2QuIEJ1dCBhaGhoaGguLi4gdGhlIGFnZSBncm91cHMgZG9uJ3QgYWxpZ24gd2l0aCB0aGUgY2FzZSBub3RpZmljYXRpb24gYWdlIGdyb3VwcyEgQ29tZSBiYWNrIHRvIHRoaW5rIGFib3V0IHRoaXMgbGF0ZXIuCgoKIyMjIDQuIFR1YmVyY3Vsb3NpcyBjYXNlcwoKSW1wb3J0IHRoZSB0dWJlcmN1bG9zaXMgY2FzZXMgZGF0YXNldAoKCiMjIyMgNC4xIE92ZXJhbGwgbm90aWZpY2F0aW9ucwoKT3ZlcmFsbCwgYnkgeWVhci4KCmBgYHtyfQoKY2FzZXNfYnlfeWVhciA8LSByZWFkX3hsc3goIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImJ5X3llYXIiKQoKY2FzZXNfYnlfeWVhciU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV95ZWFyIDwtIGNhc2VzX2J5X3llYXIgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpgYGAKClBsb3QgdGhlIG92ZXJhbGwgbnVtYmVyIG9mIGNhc2Ugbm90aWZpZWQgcGVyIHllYXIsIGJ5IHB1bG1vbmFyeSBhbmQgZXh0cmEgcHVsbW9uYXJ5IGNsYXNzaWZpY2F0aW9uLgoKYGBge3J9CgpjYXNlc19ieV95ZWFyICU+JQogIHNlbGVjdCgtdG90YWxfbm90aWZpY2F0aW9ucywgLXllYXIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhwdWxtb25hcnlfbm90aWZpY2F0aW9ucywgYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2ApKSAlPiUKICBtdXRhdGUobmFtZSA9IGNhc2Vfd2hlbihuYW1lID09ICJwdWxtb25hcnlfbm90aWZpY2F0aW9ucyIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXZhbHVlLCB4PXllYXIyLCBncm91cCA9IG5hbWUsIGZpbGw9bmFtZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk51bWJlciBvZiBjYXNlcyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICAKCmBgYAoKIyMjIyA0LjIgTm90aWZpY2F0aW9ucyBieSBEaXZpc2lvbgoKUmVhZCBpbiB0aGUgZGF0YXNldHMgYW5kIG1lcmdlIHRvZ2V0aGVyLgoKYGBge3J9CgojbGlzdCBhbGwgdGhlIHNoZWV0cwphbGxfc2hlZXRzIDwtIGV4Y2VsX3NoZWV0cygiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IikKCiNnZXQgdGhlIHdhcmQgc2hlZXRzCndhcmRfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJieV93YXJkIiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCmNhc2VzX2J5X3dhcmRfc2V4X3llYXIgPC0gbWFwX2RmKHdhcmRfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKCkFnZ3JlZ2F0ZSB0b2dldGhlciB0byBnZXQgY2FzZXMgYnkgZGl2aXNpb24KCmBgYHtyfQoKY2FzZXNfYnlfZGl2aXNpb24gPC0gY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBsZWZ0X2pvaW4od2FyZF9sb29rdXApICU+JQogIGdyb3VwX2J5KGRpdmlzaW9uLCB5ZWFyLCB0Yl90eXBlKSAlPiUKICBzdW1tYXJpc2UoY2FzZXMgPSBzdW0oY2FzZXMsIG5hLnJtID0gVFJVRSkpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV9kaXZpc2lvbiA8LSBjYXNlc19ieV9kaXZpc2lvbiAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkgJT4lCiAgdW5ncm91cCgpCgpjYXNlc19ieV9kaXZpc2lvbiAgJT4lCiAgc2VsZWN0KC15ZWFyMikgJT4lCiAgc2VsZWN0KHllYXIsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKCmNhc2VzX2J5X2RpdmlzaW9uICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1jYXNlcywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAoZGl2aXNpb25+Liwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBub3RpZmljYXRpb25zIGJ5IERpdmlzaW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpgYGAKCiMjIyMgNC4zIE5vdGlmaWNhdGlvbnMgYnkgd2FyZAoKYGBge3J9CgoKY2FzZXNfYnlfd2FyZCA8LSBjYXNlc19ieV93YXJkX3NleF95ZWFyICU+JQogIGdyb3VwX2J5KHdhcmQsIHllYXIsIHRiX3R5cGUpICU+JQogIHN1bW1hcmlzZShjYXNlcyA9IHN1bShjYXNlcywgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpCgpjYXNlc19ieV93YXJkICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgc2VsZWN0KHllYXIsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CmNhc2VzX2J5X3dhcmQgPC0gY2FzZXNfYnlfd2FyZCAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCmNhc2VzX2J5X3dhcmQgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWNhc2VzLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuOCkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcCh3YXJkfi4sIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgbm90aWZpY2F0aW9ucyBieSBXYXJkIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgpgYGAKCiMjIyMgNC40IE5vdGlmaWNhdGlvbnMgYnkgYWdlIGFuZCBzZXgKCkFzIHdlIGRvbid0IGhhdmUgZGVub21pbmF0b3JzLCB3ZSB3aWxsIGp1c3QgbW9kZWwgdGhlIGNoYW5nZSBpbiBjb3VudHMuCgpgYGB7cn0KCiNsaXN0IGFsbCB0aGUgc2hlZXRzCmFsbF9zaGVldHMgPC0gZXhjZWxfc2hlZXRzKCIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giKQoKI2dldCB0aGUgd2FyZCBzaGVldHMKYWdlX3NleF9zaGVldHMgPC0gZW5mcmFtZShhbGxfc2hlZXRzKSAlPiUKICBmaWx0ZXIoZ3JlcGwoImJ5X2FnZV9zZXgiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKY2FzZXNfYnlfYWdlX3NleCA8LSBtYXBfZGYoYWdlX3NleF9zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpjYXNlc19ieV9hZ2Vfc2V4ICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgoKCiMjIyA1IFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzCgojIyMjIDUuMSBPdmVyYWxsIFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzCgpOb3cgY2FsY3VsYXRlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIHBlciAxMDAsMDAwIHBvcHVsYXRpb24KCk1lcmdlIHRoZSBub3RpZmljYXRpb24gYW5kIHBvcHVsYXRpb24gZGVub21pbmF0b3IgZGF0YXNldHMgdG9nZXRoZXIuCgpIZXJlIHdlIG5lZWQgdG8gaW5jbHVkZSB0aGUgd2hvbGUgcG9wdWxhdGlvbiAod2l0aCBzaGlwcGluZyBhbmQgaW5zdGl0dXRpb25zKSBhcyB0aGV5IGFyZSBpbmNsdWRlZCBpbiB0aGUgbm90aWZpY2F0aW9ucy4KCmBgYHtyfQoKb3ZlcmFsbF9pbmMgPC0gb3ZlcmFsbF9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV95ZWFyKQoKb3ZlcmFsbF9pbmMgPC0gb3ZlcmFsbF9pbmMgJT4lCiAgbXV0YXRlKGluY19wdWxtXzEwMGsgPSBwdWxtb25hcnlfbm90aWZpY2F0aW9ucy90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCwKICAgICAgICAgaW5jX2VwXzEwMGsgPSBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYC90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCwKICAgICAgICAgaW5jXzEwMGsgPSB0b3RhbF9ub3RpZmljYXRpb25zL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKQoKb3ZlcmFsbF9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIGluY18xMDBrLCBpbmNfcHVsbV8xMDBrLCBpbmNfZXBfMTAwaykgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhpbmNfMTAwaywgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpgYGB7cn0KCm92ZXJhbGxfaW5jICU+JQogIHNlbGVjdCh5ZWFyMiwgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhpbmNfcHVsbV8xMDBrLCBgaW5jX2VwXzEwMGtgKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBjYXNlX3doZW4obmFtZSA9PSAiaW5jX3B1bG1fMTAwayIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJpbmNfZXBfMTAwayIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dmFsdWUsIHg9eWVhcjIsIGdyb3VwID0gbmFtZSwgZmlsbD1uYW1lKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCgpgYGAKCiMjIyMgNS4yIFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIGJ5IERpdmlzaW9uCgpgYGB7cn0KCmRpdmlzaW9uX2luYyA8LSBkaXZpc2lvbl9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV9kaXZpc2lvbikKCgpkaXZpc2lvbl9pbmMgPC0gZGl2aXNpb25faW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKQoKZGl2aXNpb25faW5jICU+JQogIHNlbGVjdCh5ZWFyLCBkaXZpc2lvbiwgdGJfdHlwZSwgaW5jXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKYGBge3J9CgpkaXZpc2lvbl9pbmMgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWluY18xMDBrLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcChkaXZpc2lvbn4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKYGBgCgojIyMjIDUuMiBUQiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlcyBieSBXYXJkCgpIZXJlIHdlIHdpbGwgZmlsdGVyIG91dCB0aGUgaW5zdGl0dXRpb25zIGFuZCBoYXJib3VyIGZyb20gdGhlIGRlbm9taW5hdG9ycywgYXMgd2UgZG9uJ3QgaGF2ZSByZWxpYWJsZSBwb3B1bGF0aW9uIGRlbm9taW5hdG9ycyBmb3IgdGhlbS4KCmBgYHtyfQoKd2FyZF9pbmMgPC0gd2FyZF9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV93YXJkKQoKCndhcmRfaW5jIDwtIHdhcmRfaW5jICU+JQogIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKQoKd2FyZF9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIHdhcmQsIHRiX3R5cGUsIGluY18xMDBrKSAlPiUKICBtdXRhdGVfYXQoLnZhcnMgPSB2YXJzKGluY18xMDBrKSwKICAgICAgICAgICAgLmZ1bnMgPSBmdW5zKHJvdW5kKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCgpgYGB7cn0KCndhcmRfaW5jICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1pbmNfMTAwaywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSwgYnkgV2FyZCIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiSW5jaWRlbmNlIChwZXIgMTAwLDAwMCkiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgoKCmBgYAoKT24gYSBtYXAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQoKc3RfYXNfc2YobGVmdF9qb2luKHdhcmRfaW5jLCBnbGFzZ293X3dhcmRzXzE5NTEpKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWluY18xMDBrKSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sID0gNykgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hbWU9IkNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgKHBlciAxMDAsMDAwKSIsCiAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gIkEiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDIsICJjbSIpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBndWlkZXMoZmlsbD1ndWlkZV9jb2xvcmJhcih0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiKSkKCgoKYGBgCgoKIyMjIDYuIFRCIE1vcnRhbGl0eQoKIyMjIyA2LjEgT3ZlcmFsbCBNb3J0YWxpdHkKCkltcG9ydCB0aGUgVEIgbW9ydGFsaXR5IGRhdGEuCgpGaXJzdCwgb3ZlcmFsbCBkZWF0aHMuIE5vdGUgdGhhdCBpbiB0aGUgb3JpZ2luYWwgcmVwb3J0cywgd2UgaGF2ZSBhIHB1bG1vbmFyeSBUQiBkZWF0aCByYXRlIHBlciBtaWxsaW9uIGZvciBhbGwgeWVhcnMsIGFuZCBudW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBkZWF0aHMgZm9yIGVhY2ggeWVhciBhcGFydCBmcm9tIDE5NTAuCgpgYGB7cn0KCiNnZXQgdGhlIG92ZXJhbGwgbW9ydGFsaXR5IHNoZWV0cwpkZWF0aHNfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJkZWF0aHMiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKb3ZlcmFsbF9kZWF0aHMgPC0gbWFwX2RmKGRlYXRoc19zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpvdmVyYWxsX2RlYXRocyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgoKCmBgYAoKUGxvdCB0aGUgcmF3IG51bWJlcnMgb2YgcHVsbW9uYXJ5IGRlYXRocwoKYGBge3J9CgpvdmVyYWxsX2RlYXRocyAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT1wdWxtb25hcnlfZGVhdGhzKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiI0RFMEQ5MiIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjREUwRDkyIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBsYWJzKHk9IlB1bG1vbmFyeSBUQiBkZWF0aHMgcGVyIHllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHRpdGxlID0gIk51bWJlcnMgb2YgcHVsbW9uYXJ5IFRCIGRlYXRocyIsCiAgICAgICBzdWJ0aXRsZSA9ICJHbGFzZ293LCAxOTUwLTE5NjMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogbm8gZGF0YSBmb3IgMTk1MCIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgpgYGAKCk5vdyB0aGUgaW5jaWRlbmNlIG9mIHB1bG1vbmFyeSBUQiBkZWF0aAoKYGBge3J9Cm92ZXJhbGxfZGVhdGhzICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXB1bG1vbmFyeV9kZWF0aF9yYXRlX3Blcl8xMDBrKSkgKwogIGdlb21fbGluZShjb2xvdXIgPSAiIzRENkNGQSIpICsKICBnZW9tX3BvaW50KGNvbG91ciA9ICIjNEQ2Q0ZBIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoeT0iQW5udWFsIGluY2lkZW5jZSBvZiBkZWF0aCAocGVyIDEwMCwwMDApIiwKICAgICAgIHggPSAiWWVhciIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczcucG5nIiksIHdpZHRoPTEwKQoKYGBgCgoKIyMjIDYuIFRhYmxlIDEKCk1ha2UgVGFibGUgMSBoZXJlLCBhbmQgc2F2ZSBmb3IgcHVibGljYXRpb24uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUgCiAgc2VsZWN0KHllYXIsIHRvdGFsX3BvcHVsYXRpb24pICU+JQogIGxlZnRfam9pbihvdmVyYWxsX2luYyAlPiUKICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgCiAgICAgICAgICAgICAgICAgICAgIHB1bG1vbmFyeV9ub3RpZmljYXRpb25zLCBpbmNfcHVsbV8xMDBrLAogICAgICAgICAgICAgICAgICAgICBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYCwgaW5jX2VwXzEwMGssCiAgICAgICAgICAgICAgICAgICAgIHRvdGFsX25vdGlmaWNhdGlvbnMsIGluY18xMDBrKSkgJT4lCiAgbGVmdF9qb2luKG92ZXJhbGxfZGVhdGhzICU+JQogICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLAogICAgICAgICAgICAgICAgICAgICBwdWxtb25hcnlfZGVhdGhzLCBwdWxtb25hcnlfZGVhdGhfcmF0ZV9wZXJfMTAwaykpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfnJvdW5kKC4sIGRpZ2l0cz0xKSkpICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgCgpgYGAKCgpQcmVwYXJlIHRoZSBkYXRhc2V0cyBmb3IgbW9kZWxsaW5nCgpgYGB7cn0KCm1kYXRhIDwtIHdhcmRfaW5jICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCm1kYXRhX2V4dHJhcHVsbW9uYXJ5IDwtIHdhcmRfaW5jICU+JQogIGZpbHRlcih0Yl90eXBlPT0iTm9uLVB1bG1vbmFyeSIpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKHllYXIgJWluJSBjKDE5NTA6MTk1NikgfiAiYS4gcHJlLWFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1NykgfiAiYi4gYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU4OjE5NjMpIH4gImMuIHBvc3QtYWNmIikpICU+JQogIGdyb3VwX2J5KHdhcmQpICU+JQogIG11dGF0ZSh5X251bSA9IHJvd19udW1iZXIoKSkgJT4lCiAgdW5ncm91cCgpCgoKI3NjYWZmb2xkIGZvciBvdmVyYWxsIHByZWRpY3Rpb25zCm92ZXJhbGxfc2NhZmZvbGQgPC0gbWRhdGEgJT4lCiAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB3YXJkLCBjYXNlcykgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QpICU+JQogICAgc3VtbWFyaXNlKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAgPSBzdW0ocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCksCiAgICAgICAgICAgICAgY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICAgIGxlZnRfam9pbihtZGF0YV9leHRyYXB1bG1vbmFyeSAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgICAgICAgICAgICBzdW1tYXJpc2UoY2FzZXNfZXh0cmFwdWxtb25hcnkgPSBzdW0oY2FzZXMpKSkgJT4lCiAgICBtdXRhdGUoaW5jXzEwMGtfZXh0cmFwdWxtb25hcnkgPSBjYXNlc19leHRyYXB1bG1vbmFyeS9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkKCmBgYAoKCiMjIyA3LiBQdWxtb25hcnkgVEIgbW9kZWwKCiMjIyMgNy4xIEZpdCB0aGUgbW9kZWwgYW5kIHByaW9ycwoKVGhpcyBtb2RlbHMgdGhlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgb3ZlciB0aW1lLCB3aXRoIGEgc3RlcCBjaGFuZ2UgZm9yIHRoZSBpbnRlcnZlbnRpb24sIGFuZCBzbG9wZSBjaGFuZ2UgYWZ0ZXIgdGhlIGludGVydmVudGlvbi4KCldvcmsgb24gdGhlIHByaW9ycyBhIGJpdC4gV2Ugd2lsbCBidWlsZCB1cCBmcm9tIGxlc3MgY29tcGxleCB0byBtb3JlIGNvbXBsZXguCgphKSBpbnRlcmNlcHQgb25seSwgdG8gcHJlZGljdCBjb3VudCBvZiBjYXNlcwoKYXQgdGhlIGludGVyY2VwdCwgd2UgZXhwZWN0IHNvbWV3aGVyZSBhcm91bmQgMjUwMC4gV2Ugd2lsbCBzZXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiB0byBib3RoIDAuNSBhbmQgMSB0byBjaGVjayB3aGF0IGl0IGxvb2tzIGxpa2UKCmBgYHtyfQoKYyhwcmlvcihsb2dub3JtYWwoNy42MDA5MDIsIDAuNSkpLCAjbG9nKDI1MDApID0gNy42MDA5MDIKICBwcmlvcihsb2dub3JtYWwoNy42MDA5MDIsIDEpKSkgJT4lIAogIHBhcnNlX2Rpc3QoKSAlPiUgCiAgCiAgZ2dwbG90KGFlcyh5ID0gcHJpb3IsIGRpc3QgPSAuZGlzdCwgYXJncyA9IC5hcmdzKSkgKwogIHN0YXRfaGFsZmV5ZSgud2lkdGggPSBjKC41LCAuOTUpKSArCiAgc2NhbGVfeV9kaXNjcmV0ZShOVUxMLCBsYWJlbHMgPSBzdHJfYygibG9nbm9ybWFsKGxvZygyMDAwKSwgIiwgYygwLjUsIDEpLCAiKSIpLAogICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMSkpICsKICB4bGFiKGV4cHJlc3Npb24oZXhwKGl0YWxpYyhwKShiZXRhWzBdKSkpKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsMTUwMDApKQoKCnByaW9yKGdhbW1hKDEsIDAuMDEpKSAlPiUKICBwYXJzZV9kaXN0KCkgJT4lCiAgZ2dwbG90KGFlcyh5PXByaW9yLCBkaXN0ID0gLmRpc3QsIGFyZ3MgPSAuYXJncykpICsKICBzdGF0X2hhbGZleWUoLndpZHRoID0gYygwLjUsIDAuOTUpKQoKI25vdyBmaXQgdG8gYSBtb2RlbCwgYW5kIHBsb3Qgc29tZSBwcmlvciByZWFsaXNhdGlvbnMKCm1fcHJpb3IxIDwtIGJybSgKICBjYXNlcyB+IDAgKyBJbnRlcmNlcHQsCiAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICBkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwKICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiAgcHJpb3IgPSBwcmlvcihub3JtYWwobG9nKDIwMDApLCAwLjUpLCBjbGFzcyA9IGIsIGNvZWYgPSBJbnRlcmNlcHQpICsKICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKQopCgphZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IxLAogICAgICAgICAgICAgICAgbmV3ZGF0YSA9IHRpYmJsZShpbnRlcmNlcHQ9MSkpICU+JQogIGdncGxvdChhZXMoeD1pbnRlcmNlcHQsIHk9LmVwcmVkKSkgKwogIHN0YXRfaGFsZmV5ZSgpICsKICBzY2FsZV95X2xvZzEwKGxhYmVscyA9IGNvbW1hKQoKCmBgYAoKTm93IHRyeSB0byBhZGQgaW4gYSB0ZXJtIGZvciB0aGUgZWZmZWN0IG9mIHlfbnVtLiBXZSBhbnRpY3BhdGUgdGhhdCB0aGUgbnVtYmVyIG9mIGNhc2VzIHdpbGwgZGVjbGluZSBieSBhYm91dCAxLTUlIHBlciB5ZWFyLiBIb3dldmVyLCBhcyB3ZSBhcmUgcHJldHR5IHVuY2VydGFpbiBhYm91dCB0aGlzLCB3ZSB3aWxsIGp1c3QgZW5jb2RlIGEgd2Vha2x5IHJlZ3VsYXJpc2luZyBwcmlvciB0byByZXN0cmljdCB0aGUgeWVhciBzaXplIHRvIHNlbnNpYmxlIHJhbmdlcy4KCmBgYHtyfQoKCm1fcHJpb3IyIDwtIGJybSgKICBjYXNlcyB+IDAgKyBJbnRlcmNlcHQgKyB5X251bSwKICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogIGRhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLAogIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coMjAwMCksIDAuNSksIGNsYXNzID0gYiwgY29lZiA9IEludGVyY2VwdCkgKwogICAgICAgICAgcHJpb3IoZ2FtbWEoMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiLCBjb2VmID0geV9udW0pCikKCmFkZF9lcHJlZF9kcmF3cyhvYmplY3Q9bV9wcmlvcjIsCiAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9LmVwcmVkKSkgKwogIHN0YXRfaGFsZmV5ZSgpICsKICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKQoKYGBgCgpOb3cgd2Ugd2FudCB0byBhZGQgaW4gYSBwcmlvciBmb3IgdGhlIGVmZmVjdCBvZiB0aGUgYWNmX2ludGVydmVudGlvbi4gV2UgYW50aWNpcGF0ZSB0aGUgcGVhayB0byBiZSBhbnl3aGVyZSBiZXR3ZWVuIG5vIGVmZmVjdCwgYW5kIGEgdHJpcGxpbmcKCmBgYHtyfQoKbV9wcmlvcjMgPC0gYnJtKAogIGNhc2VzIH4gMCArIEludGVyY2VwdCArIHlfbnVtICsgYWNmX3BlcmlvZCwKICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogIGRhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLAogIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coMjAwMCksIDAuNSksIGNsYXNzID0gYiwgY29lZiA9IEludGVyY2VwdCkgKwogICAgICAgICAgcHJpb3IoZ2FtbWEoMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiLCBjb2VmID0geV9udW0pICsKICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAwMSksIGNsYXNzID0gYikKKQoKCmFkZF9lcHJlZF9kcmF3cyhvYmplY3Q9bV9wcmlvcjMsCiAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9LmVwcmVkKSkgKwogIHN0YXRfaGFsZmV5ZSgpICsKICBzY2FsZV95X2xvZzEwKGxhYmVscyA9IGNvbW1hKQoKCgpgYGAKCk5vdyB3ZSBsb29rIGFuZCBzZWUgd2hhdCBpdCBsb29rcyBsaWtlIHdpdGggdGhlIGludGVyYWN0aW9ucwoKYGBge3J9CgptX3ByaW9yNCA8LSBicm0oCiAgY2FzZXMgfiAwICsgSW50ZXJjZXB0ICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgeV9udW06YWNmX3BlcmlvZCwKICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogIGRhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLAogIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coMjUwMCksIDEpLCBjbGFzcyA9IGIsIGNvZWYgPSBJbnRlcmNlcHQpICsKICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMSksIGNsYXNzID0gYikKKQoKYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNCwKICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBvdmVyYWxsX3NjYWZmb2xkKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiAgc3RhdF9oYWxmZXllKCkgKwogIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpCgoKCmBgYAoKTm93IHRyeSBhZGRpbmcgaW4gdGhlIHJhbmRvbSBpbnRlcmNlcHRzCgpgYGB7cn0KCmMocHJpb3IobG9nbm9ybWFsKDMuOTEyMDIzLCAwLjUpKSwgI2xvZyg1MCkgPSAzLjkxMjAyMwogIHByaW9yKGxvZ25vcm1hbCgzLjkxMjAyMywgMSkpKSAlPiUgCiAgcGFyc2VfZGlzdCgpICU+JSAKICAKICBnZ3Bsb3QoYWVzKHkgPSBwcmlvciwgZGlzdCA9IC5kaXN0LCBhcmdzID0gLmFyZ3MpKSArCiAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoLjUsIC45NSkpICsKICBzY2FsZV95X2Rpc2NyZXRlKE5VTEwsIGxhYmVscyA9IHN0cl9jKCJsb2dub3JtYWwobG9nKDUwKSwgIiwgYygwLjUsIDEpLCAiKSIpLAogICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMSkpICsKICB4bGFiKGV4cHJlc3Npb24oZXhwKGl0YWxpYyhwKShiZXRhWzBdKSkpKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsNDAwKSkKCgptX3ByaW9yNSA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kICsgKCAxIHwgd2FyZCksCiAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICBkYXRhID0gbWRhdGEsCiAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAogIHByaW9yID0gcHJpb3Iobm9ybWFsKGxvZyg1MCksIDEpLCBjbGFzcyA9IEludGVyY2VwdCkgKwogICAgICAgICAgcHJpb3IoZ2FtbWEoMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKSArCiAgICAgICAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3M9c2QpCikKCgphZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3I1LAogICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhLAogICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IE5BKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiAgc3RhdF9oYWxmZXllKCkgKwogIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpCgphZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3I1LAogICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhLAogICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IE5BKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiAgc3RhdF9oYWxmZXllKCkgKwogIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpICsKICBmYWNldF93cmFwKHdhcmR+LikKCmBgYAoKQW5kIGFkZCBpbiB0aGUgcmFuZG9tIHNsb3BlcwoKYGBge3J9CgptX3ByaW9yNiA8LSBicm0oCiAgY2FzZXMgfiAxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgeV9udW06YWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpLAogIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgZGF0YSA9IG1kYXRhLAogIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKICBwcmlvciA9IHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4xKSwgY2xhc3MgPSBiKSArCiAgICAgICAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3M9c2QpICsKICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9Y29yKQopCgoKCm1fcHJpb3I2IDwtIGJybSgKICBjYXNlcyB+IDAgKyBJbnRlcmNlcHQgKyB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kICsgKCB5X251bSphY2ZfcGVyaW9kIHwgd2FyZCksCiAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICBkYXRhID0gbWRhdGEsCiAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAogIHByaW9yID0gcHJpb3Iobm9ybWFsKGxvZyg1MCksIDEpLCBjbGFzcyA9IGIsIGNvZWYgPSBJbnRlcmNlcHQpICsKICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMSksIGNsYXNzID0gYikgKwogICAgICAgICAgcHJpb3IoZXhwb25lbnRpYWwoMTAwKSwgY2xhc3M9c2QpICsKICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9Y29yKQopCgoKYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNiwKICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YSwKICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSBOQSkgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9LmVwcmVkKSkgKwogIHN0YXRfaGFsZmV5ZSgpICsKICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKQoKYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNiwKICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YSwKICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KCAxICsgeV9udW0gKyBhY2ZfcGVyaW9kIHwgd2FyZCkpICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PS5lcHJlZCkpICsKICBzdGF0X2hhbGZleWUoKSArCiAgc2NhbGVfeV9sb2cxMChsYWJlbD1jb21tYSkgKwogIGZhY2V0X3dyYXAod2FyZH4uKQoKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWw9bV9wcmlvcjYsIG91dGNvbWUgPSBpbmNfMTAwaywgCiAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHJlX2Zvcm11bGEgPSBOQSkKCnBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhLCBtb2RlbD1tX3ByaW9yNiwgb3V0Y29tZSA9IGluY18xMDBrLCAKICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCwKICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gfiggMSArIHlfbnVtICsgYWNmX3BlcmlvZCB8IHdhcmQpKQoKYGBgCgoKSXNzdWUgaGVyZSBpcyB0aGUgbm9uLWNlbnRyZWQgcGFyYW1ldGVyaXNhdGlvbiBvZiB0aGUgaW50ZXJjZXB0IHByaW9yLi4uIEZlZWwgbGlrZSB0aGlzIGlzIGEgbW9yZSBpbnRlcnByZXRhYmxlIHdheSB0byBzZXQgcHJpb3JzLi4uIGJ1dCB3aWxsIHJldmVydCB0byBjZW50cmVkIHBhcmFtZXRlcmlzYXRpb24gZm9yIHRoZSBtZWFudGltZS4KCgpMb29rIGF0IHRoZSBtZWFuIGFuZCB2YXJpYW5jZSBvZiBjb3VudHMgKGNvdW50cyBvZiBwdWxtb25hcnkgbm90aWZpY2F0aW9ucyBhcmUgd2hhdCB3ZSBhcmUgcHJlZGljdGluZykKCmBgYHtyfQoKI01lYW4gb2YgY291bnRzIHBlciB5ZWFyCm1lYW4obWRhdGEkY2FzZXMpCiN2YXJpYW5jZSBvZiBjb3VudHMgcGVyIHllYXIKdmFyKG1kYXRhJGNhc2VzKQoKYGBgCgoKUXVpdGUgYSBiaXQgb2Ygb3Zlci1kaXNwZXJzaW9uIGhlcmUsIHNvIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBtaWdodCBiZSBhIGJldHRlciBjaG9pY2Ugb2YgZGlzdHJpYnV0aW9uYWwgZmFtaWx5IHRoYW4gUG9pc3Nvbi4KCkZpdCB0aGUgbW9kZWwgd2l0aCB0aGUgZGF0YQoKYGBge3J9CgptX3B1bG1vbmFyeSA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kICsgKHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSArIG9mZnNldChsb2cocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGEsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsCiAgICAgICAgICAgICAgICAgIHByaW9yID0gcHJpb3IoZ2FtbWEoMC4wMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4xKSwgY2xhc3MgPSBiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IoZXhwb25lbnRpYWwoMSksIGNsYXNzPXNkKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz1jb3IpKQogIAojY2hlY2sgbW9kZWwgZGlhZ25vc3RpY3MKc3VtbWFyeShtX3B1bG1vbmFyeSkKcGxvdChtX3B1bG1vbmFyeSkKcHBfY2hlY2sobV9wdWxtb25hcnksIHR5cGU9J2VjZGZfb3ZlcmxheScpCgpgYGAKCgojIyMjIDcuMiBTdW1tYXJpc2UgY2hhbmdlIGluIENOUnMKClN1bW1hcmlzZSB0aGUgcG9zdGVyaW9yIGluIGdyYXBoaWNhbCBmb3JtCgpgYGB7cn0KCmYxYiA8LSBwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLCBtb2RlbCA9IG1fcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIG91dGNvbWUgPSBpbmNfMTAwaywgZ3JvdXBpbmdfdmFyPU5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSBOQSkKICAKZjFiCmBgYAoKTWFrZSB0aGlzIGludG8gYSBmaWd1cmUgY29tYmluZWQgd2l0aCB0aGUgbWFwIG9mIGVtcGlyaWNhbCBkYXRhCgpgYGB7cn0KCmYxYSA8LSBzdF9hc19zZihsZWZ0X2pvaW4od2FyZF9pbmMsIGdsYXNnb3dfd2FyZHNfMTk1MSkpICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGw9aW5jXzEwMGspKSArCiAgZmFjZXRfd3JhcCh5ZWFyfi4sIG5jb2wgPSA3KSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobmFtZT0iQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAjbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMiwgImNtIiksCiAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMC41KSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfY29sb3JiYXIodGl0bGUucG9zaXRpb24gPSAidG9wIikpCgooZjFhIC8gZjFiKSArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gIkEiKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvZjEucG5nIikpCgpgYGAKClN1bW1hcnkgb2YgY2hhbmdlIGluIG5vdGlmaWNhdGlvbnMgbnVtZXJpY2FsbHkKCmBgYHtyfQoKb3ZlcmFsbF9jaGFuZ2UgPC0gc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsPW1fcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yPXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3Zhcj1OVUxMLCByZV9mb3JtdWxhID0gTkEpCgojd2FudCB0byBrZWVwIHRoZSBzdW1tYXJ5IGVzdGltYXRlcyBoZXJlCnRva2VlcCA8LSBjKCJwZWFrX3N1bW1hcnkiLCAibGV2ZWxfc3VtbWFyeSIsICJzbG9wZV9zdW1tYXJ5IikKCiNzdW1tYXJ5IG1lYXN1cmVzIGluIGEgdGFibGUKb3ZlcmFsbF9jaGFuZ2UgJT4lCiAga2VlcCgobmFtZXMoLikgJWluJSB0b2tlZXApKSAlPiUKICBiaW5kX3Jvd3MoKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoZXN0aW1hdGU6LnVwcGVyKSwgbnVtYmVyLCBhY2N1cmFjeT0wLjAxKSkgJT4lCiAgc2VsZWN0KG1lYXN1cmUsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiAgCmBgYAoKCiMjIyMgNy4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpOdW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGNvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsIHBlciB5ZWFyLgoKYGBge3J9CgpvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiA8LSBjYWxjdWxhdGVfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsPW1fcHVsbW9uYXJ5LCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkKCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyLCBkaWZmX2luYzEwMGs6ZGlmZl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHJyX2luYzEwMGs6cnJfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKVG90YWwgcHVsbW9uYXJ5IFRCIGNhc2VzIGF2ZXJ0ZWQgYmV0d2VlbiAxOTU4IGFuZCAxOTYzCgpgYGB7cn0KCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCiMjIyMgNy40IENvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhaywgUlIubGV2ZWwsIGFuZCBSUi5zbG9wZQoKV2hhdCBhcmUgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHBlYWssIGxldmVsLCBhbmQgc2xvcGU/CgpgYGB7cn0KCiNSUi5wZWFrIGhpc3RvZ3JhbQphIDwtIG92ZXJhbGxfY2hhbmdlJHBlYWtfZHJhd3MgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PWVzdGltYXRlKSwgZmlsbD0iZGFya2JsdWUiLCBjb2xvdXI9ImRhcmtibHVlIiwgYWxwaGE9MC4zKSsKICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9ImxpZ2h0Ymx1ZTEiLGxvdz0iZGFya2JsdWUiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgbGFicyh4PSJSUi5wZWFrIiwKICAgICAgIHk9IiIpCgojUlIuIGxldmVsIGhpc3RvZ3JhbQpiIDwtIG92ZXJhbGxfY2hhbmdlJGxldmVsX2RyYXdzICAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9ZXN0aW1hdGUpLCBmaWxsPSJkYXJrYmx1ZSIsIGNvbG91cj0iZGFya2JsdWUiLCBhbHBoYT0wLjMpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IlJSLmxldmVsIiwKICAgICAgIHk9IiIpCgojUlIuc2xvcGUgaGlzdG9ncmFtCmMgPC0gb3ZlcmFsbF9jaGFuZ2Ukc2xvcGVfZHJhd3MgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PWVzdGltYXRlKSwgZmlsbD0iZGFya2JsdWUiLCBjb2xvdXI9ImRhcmtibHVlIiwgYWxwaGE9MC4zKSsKICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9ImxpZ2h0Ymx1ZTEiLGxvdz0iZGFya2JsdWUiKSArICAKICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA2KSkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGxhYnMoeD0iUlIuc2xvcGUiLAogICAgICAgeT0iIikKCgojQ29ycmVsYXRpb24gYmV0d2VlbiBSUi5wZWFrIGFuZCBSUi5sZXZlbApjb3JfcnJfcGVha19ycl9sZXZlbCA8LSByb3VuZChjb3IocGx1Y2sob3ZlcmFsbF9jaGFuZ2UkcGVha19kcmF3cyRlc3RpbWF0ZSksIHBsdWNrKG92ZXJhbGxfY2hhbmdlJGxldmVsX2RyYXdzJGVzdGltYXRlKSksIGRpZ2l0cyA9IDIpCgojQ29ycmVsYXRpb24gYmV0d2VlbiBSUi5wZWFrIGFuZCBSUi5zbG9wZQpjb3JfcnJfcGVha19ycl9zbG9wZSA8LSByb3VuZChjb3IocGx1Y2sob3ZlcmFsbF9jaGFuZ2UkcGVha19kcmF3cyRlc3RpbWF0ZSksIHBsdWNrKG92ZXJhbGxfY2hhbmdlJHNsb3BlX2RyYXdzJGVzdGltYXRlKSksIGRpZ2l0cyA9IDIpCgojQ29ycmVsYXRpb24gYmV0d2VlbiBSUi5sZXZlbCBhbmQgUlIuc2xvcGUKY29yX3JyX2xldmVsX3JyX3Nsb3BlIDwtIHJvdW5kKGNvcihwbHVjayhvdmVyYWxsX2NoYW5nZSRsZXZlbF9kcmF3cyRlc3RpbWF0ZSksIHBsdWNrKG92ZXJhbGxfY2hhbmdlJHNsb3BlX2RyYXdzJGVzdGltYXRlKSksIGRpZ2l0cyA9IDIpCgoKI3Bsb3Qgb2YgY29ycmVsYXRpb24gYmV0d2VlbiBSUi5wZWFrIGFuZCBSUi5sZXZlbApkIDwtIGJpbmRfY29scyhSUi5wZWFrPXBsdWNrKG92ZXJhbGxfY2hhbmdlJHBlYWtfZHJhd3MkZXN0aW1hdGUpLCAKICAgICAgICAgIFJSLmxldmVsID1wbHVjayhvdmVyYWxsX2NoYW5nZSRsZXZlbF9kcmF3cyRlc3RpbWF0ZSkpICU+JQogIGdncGxvdChhZXMoeT1SUi5wZWFrLCB4ID0gUlIubGV2ZWwpKSArCiAgZ2VvbV9oZXgoKSArCiAgZ2VvbV9zbW9vdGgoc2U9RkFMU0UsIGNvbG91cj0iZmlyZWJyaWNrIiwgbWV0aG9kID0gImxtIikgKwogIGdlb21fdGV4dChhZXMoeT0yLjIsIHg9MC41OCwgbGFiZWw9Y29yX3JyX3BlYWtfcnJfbGV2ZWwpLCBjb2xvdXI9ImZpcmVicmljayIpICArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCiNwbG90IG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhayBhbmQgUlIuc2xvcGUKZSA8LSBiaW5kX2NvbHMoUlIucGVhaz1wbHVjayhvdmVyYWxsX2NoYW5nZSRwZWFrX2RyYXdzJGVzdGltYXRlKSwgCiAgICAgICAgICBSUi5zbG9wZSA9cGx1Y2sob3ZlcmFsbF9jaGFuZ2Ukc2xvcGVfZHJhd3MkZXN0aW1hdGUpKSAlPiUKICBnZ3Bsb3QoYWVzKHk9UlIucGVhaywgeCA9IFJSLnNsb3BlKSkgKwogIGdlb21faGV4KCkgKwogIGdlb21fc21vb3RoKHNlPUZBTFNFLCBjb2xvdXI9ImZpcmVicmljayIpICsKICBnZW9tX3RleHQoYWVzKHk9Mi4xLCB4PTAuNSwgbGFiZWw9Y29yX3JyX3BlYWtfcnJfc2xvcGUpLCBjb2xvdXI9ImZpcmVicmljayIpICArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgNikpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9ImxpZ2h0Ymx1ZTEiLGxvdz0iZGFya2JsdWUiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKI3Bsb3Qgb2YgY29ycmVsYXRpb24gYmV0d2VlbiBSUi5sZXZlbCBhbmQgUlIuc2xvcGUKZiA8LSBiaW5kX2NvbHMoUlIubGV2ZWw9cGx1Y2sob3ZlcmFsbF9jaGFuZ2UkbGV2ZWxfZHJhd3MkZXN0aW1hdGUpLCAKICAgICAgICAgIFJSLnNsb3BlID1wbHVjayhvdmVyYWxsX2NoYW5nZSRzbG9wZV9kcmF3cyRlc3RpbWF0ZSkpICU+JQogIGdncGxvdChhZXMoeT1SUi5sZXZlbCwgeCA9IFJSLnNsb3BlKSkgKwogIGdlb21faGV4KCkgKwogIGdlb21fc21vb3RoKHNlPUZBTFNFLCBjb2xvdXI9ImZpcmVicmljayIpICsKICBnZW9tX3RleHQoYWVzKHk9MC43NSwgeD0wLjUsIGxhYmVsPWNvcl9ycl9sZXZlbF9ycl9zbG9wZSksIGNvbG91cj0iZmlyZWJyaWNrIikgICsgIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDYpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChoaWdoPSJsaWdodGJsdWUxIixsb3c9ImRhcmtibHVlIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCgoocGxvdF9zcGFjZXIoKSArIHBsb3Rfc3BhY2VyKCkgKyBjKSAvCiAgKHBsb3Rfc3BhY2VyKCkgKyBiICsgZikgLwogIChhICsgZCArIGUpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9wdWxtb25hcnlfY29ycy5wZGYiKSwgd2lkdGg9OCwgaGVpZ2h0PTgpCgoKCmBgYAoKCiMjIyMgNy41IFdhcmQgbGV2ZWwgcHVsbW9uYXJ5IFRCIGVzdGltYXRlcwoKUGxvdCB0aGUgY291bnRlcmZhY3R1YWwgYXQgd2FyZCBsZXZlbAoKYGBge3J9CgpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YSwgbW9kZWw9bV9wdWxtb25hcnksIG91dGNvbWUgPSBpbmNfMTAwaywgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIAogICAgICAgICAgICAgICAgICAgIGdyb3VwaW5nX3ZhciA9IHdhcmQsIHdhcmQsIHJlX2Zvcm11bGE9IH4oMSArIHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSkKICAKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczQucG5nIiksIHdpZHRoPTEyLCBoZWlnaHQ9MTIpCgpgYGAKClN1bW1hcnkgb2YgY2hhbmdlIGluIG5vdGlmaWNhdGlvbnMgYXQgd2FyZCBsZXZlbAoKYGBge3J9Cgp3YXJkX2NoYW5nZSA8LSBzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGE9bWRhdGEsIG1vZGVsPW1fcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yPXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3Zhcj13YXJkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gfigxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpKQoKI3dhbnQgdG8ga2VlcCB0aGUgc3VtbWFyeSBlc3RpbWF0ZXMgaGVyZQp0b2tlZXAgPC0gYygicGVha19zdW1tYXJ5IiwgImxldmVsX3N1bW1hcnkiLCAic2xvcGVfc3VtbWFyeSIpCgojc3VtbWFyeSBtZWFzdXJlcyBpbiBhIHRhYmxlCndhcmRfY2hhbmdlICU+JQogIGtlZXAoKG5hbWVzKC4pICVpbiUgdG9rZWVwKSkgJT4lCiAgYmluZF9yb3dzKCkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGVzdGltYXRlOi51cHBlciksIG51bWJlciwgYWNjdXJhY3k9MC4wMSkpICU+JQogIHNlbGVjdChtZWFzdXJlLCBldmVyeXRoaW5nKCkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpDYWxjdWxhdGUgdGhlIGNvdW50ZXJmYWN0dWFsIHBlciB3YXJkCgpgYGB7cn0KCndhcmRfcHVsbW9uYXJ5X2NvdW50ZXJmIDwtIGNhbGN1bGF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEsIG1vZGVsPW1fcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBpbmdfdmFyID0gd2FyZCwgcmVfZm9ybXVsYT1+KDEgKyB5X251bSphY2ZfcGVyaW9kIHwgd2FyZCkpCgp3YXJkX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCk92ZXJhbGwgY291bnRlcmZhY3R1YWwgcGVyIHdhcmQKCmBgYHtyfQoKd2FyZF9wdWxtb25hcnlfY291bnRlcmYkY291bnRlcl9wb3N0X292ZXJhbGwgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgoKCiMjIyA4LiBFeHRyYS1wdWxtb25hcnkgVEIgbm90aWZpY2F0aW9ucwoKTm93IHdlIHdpbGwgbW9kZWwgdGhlIGV4dHJhLXB1bG1vbmFyeSBUQiBub3RpZmljYXRpb24gcmF0ZS4gU3RydWdnbGluZyBhIGJpdCB3aXRoIG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVsLCBzbyByZXZlcnQgdG8gUG9pc3Nvbi4KCiMjIyMgOC4xIEZpdCB0aGUgbW9kZWwKCmBgYHtyfQoKbV9leHRyYXB1bG1vbmFyeSA8LSBicm0oCiAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kICsgKHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSArIG9mZnNldChsb2cocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpLAogICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGFfZXh0cmFwdWxtb25hcnksCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IHBvaXNzb24oKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwKICAgICAgICAgICAgICAgICAgcHJpb3IgPSBwcmlvcihub3JtYWwoMCwgMC4wMSksIGNsYXNzID0gYikgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9Y29yKSkKCnN1bW1hcnkobV9leHRyYXB1bG1vbmFyeSkKcGxvdChtX2V4dHJhcHVsbW9uYXJ5KQpwcF9jaGVjayhtX2V4dHJhcHVsbW9uYXJ5LCB0eXBlPSdlY2RmX292ZXJsYXknKQoKYGBgCgojIyMjIDguMiBTdW1tYXJ5IG9mIGNoYW5nZQoKU3VtbWFyaXNlIGluIHBsb3QKCmBgYHtyfQpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLCBtb2RlbD1tX2V4dHJhcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgb3V0Y29tZT1pbmNfMTAwa19leHRyYXB1bG1vbmFyeSwgcmVfZm9ybXVsYSA9IE5BKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNi5wbmciKSwgd2lkdGg9MTApCgpgYGAKClN1bW1hcmlzZSBudW1lcmljYWxseS4KCmBgYHtyfQoKb3ZlcmFsbF9jaGFuZ2VfZXh0cmFwdWxtb25hcnkgPC0gc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsPW1fZXh0cmFwdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3I9cG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyPU5VTEwsIHJlX2Zvcm11bGEgPSBOQSkKCiN3YW50IHRvIGtlZXAgdGhlIHN1bW1hcnkgZXN0aW1hdGVzIGhlcmUKdG9rZWVwIDwtIGMoInBlYWtfc3VtbWFyeSIsICJsZXZlbF9zdW1tYXJ5IiwgInNsb3BlX3N1bW1hcnkiKQoKI3N1bW1hcnkgbWVhc3VyZXMgaW4gYSB0YWJsZQpvdmVyYWxsX2NoYW5nZV9leHRyYXB1bG1vbmFyeSAlPiUKICBrZWVwKChuYW1lcyguKSAlaW4lIHRva2VlcCkpICU+JQogIGJpbmRfcm93cygpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgojIyMjIDguMyBDb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbAoKTnVtYmVycyBvZiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBvdmVyYWxsLgoKYGBge3J9CgpvdmVyYWxsX2VwX2NvdW50ZXJmIDwtIGNhbGN1bGF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEsIG1vZGVsPW1fZXh0cmFwdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKQoKb3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKVG90YWwgZXh0cmFwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBiZXR3ZWVuIDE5NTggYW5kIDE5NjMKCmBgYHtyfQoKb3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3Rfb3ZlcmFsbCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgojIyMjIDguNCBXYXJkLWxldmVsIGV4dHJhLXB1bG1vbmFyeSBzdW1tYXJpZXMKCldhcmQtbGV2ZWwgZXh0cmEtcHVsbW9uYXJ5IGVzdGltYXRlcyBpbiBncmFwaGljYWwgZm9ybS4KCmBgYHtyfQoKcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGFfZXh0cmFwdWxtb25hcnksIG1vZGVsPW1fZXh0cmFwdWxtb25hcnksIG91dGNvbWUgPSBpbmNfMTAwaywgCiAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3ZhciA9IHdhcmQscmVfZm9ybXVsYSA9fih5X251bSphY2ZfcGVyaW9kIHwgd2FyZCksIAogICAgICAgICAgICAgICAgICAgIHdhcmQpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M0LnBuZyIpLCB3aWR0aD0xMCwgaGVpZ2h0PTEyKQoKYGBgCgpOdW1lcmljYWwgc3VtbWFyeS4KCmBgYHtyfQoKd2FyZF9jaGFuZ2VfZXh0cmFwdWxtb25hcnkgPC0gc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhID0gbWRhdGFfZXh0cmFwdWxtb25hcnksIG1vZGVsID0gbV9leHRyYXB1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3Zhcj13YXJkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSkgCgojd2FudCB0byBrZWVwIHRoZSBzdW1tYXJ5IGVzdGltYXRlcyBoZXJlCnRva2VlcCA8LSBjKCJwZWFrX3N1bW1hcnkiLCAibGV2ZWxfc3VtbWFyeSIsICJzbG9wZV9zdW1tYXJ5IikKCiNzdW1tYXJ5IG1lYXN1cmVzIGluIGEgdGFibGUKd2FyZF9jaGFuZ2VfZXh0cmFwdWxtb25hcnkgICU+JQogIGtlZXAoKG5hbWVzKC4pICVpbiUgdG9rZWVwKSkgJT4lCiAgYmluZF9yb3dzKCkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGVzdGltYXRlOi51cHBlciksIG51bWJlciwgYWNjdXJhY3k9MC4wMSkpICU+JQogIHNlbGVjdChtZWFzdXJlLCBldmVyeXRoaW5nKCkpICU+JQogIGRhdGF0YWJsZSgpCgoKCmBgYAoKCiMjIyA5LiBBZ2Utc2V4IG1vZGVsCgojIyMjIDkuMSBGSXQgdGhlIG1vZGVsCgpGaXQgdGhlIG1vZGVsCgooTm90IHJld3JpdHRlbiB0aGUgZnVuY3Rpb25zIGZvciB0aGlzIHlldCkKCmBgYHtyfQoKbWRhdGFfYWdlX3NleCA8LSBjYXNlc19ieV9hZ2Vfc2V4ICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKYmFzaWNfcHJpb3IgPC0gYyhwcmlvcihnYW1tYSgxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSksCiAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKSkKCgptX2FnZV9zZXggPC0gYnJtKAogIGNhc2VzIH4geV9udW0gKyAoYWNmX3BlcmlvZCkqKGFnZSpzZXgpICsgKGFjZl9wZXJpb2Q6eV9udW0pKihhZ2Uqc2V4KSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMjM0LAogICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsIAogICAgICAgICAgICAgICAgICBwcmlvciA9IGJhc2ljX3ByaW9yKQoKc3VtbWFyeShtX2FnZV9zZXgpCnBsb3QobV9hZ2Vfc2V4KQpwcF9jaGVjayhtX2FnZV9zZXgsIHR5cGU9J2VjZGZfb3ZlcmxheScpCgoKYGBgCgpTdW1tYXJpc2UgcG9zdGVyaW9yCgpgYGB7cn0KCiNwb3N0ZXJpb3IgZHJhd3MsIGFuZCBzdW1tYXJpc2UKYWdlX3NleF9zdW1tYXJ5IDwtIG1kYXRhX2FnZV9zZXggJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaSgpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpCgojY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQphZ2Vfc2V4X2NvdW50ZXJmYWN0IDwtIAogIHRpYmJsZSh5ZWFyID0gbWRhdGFfYWdlX3NleCR5ZWFyLAogICAgICAgICB5ZWFyMiA9IG1kYXRhX2FnZV9zZXgkeWVhcjIsCiAgICAgICAgIHlfbnVtID0gbWRhdGFfYWdlX3NleCR5X251bSwKICAgICAgICAgYWdlID0gbWRhdGFfYWdlX3NleCRhZ2UsCiAgICAgICAgIHNleCA9IG1kYXRhX2FnZV9zZXgkc2V4LAogICAgICAgICBhY2ZfcGVyaW9kID0gZmFjdG9yKCJhLiBwcmUtYWNmIikpICU+JQogIGFkZF9lcHJlZF9kcmF3cyhtX2FnZV9zZXgpICU+JQogIGdyb3VwX2J5KHllYXIyLCBhY2ZfcGVyaW9kLCBhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaSgpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0gIk0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0gIkYiIH4gIkZlbWFsZSIpKSAKCgoKYWdlX3NleF9zdW1tYXJ5ICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0gIk0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0gIkYiIH4gIkZlbWFsZSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9yaWJib24oYWVzKHltaW49LmVwcmVkLmxvd2VyLCB5bWF4PS5lcHJlZC51cHBlciwgeD15ZWFyMiwgZ3JvdXAgPSBhY2ZfcGVyaW9kLCBmaWxsPWFjZl9wZXJpb2QpLCBhbHBoYT0wLjUpICsKICBnZW9tX3JpYmJvbihkYXRhID0gYWdlX3NleF9jb3VudGVyZmFjdCAlPiUgZmlsdGVyKHllYXI+PTE5NTYpLCAKICAgICAgICAgICAgICBhZXMoeW1pbj0uZXByZWQubG93ZXIsIHltYXg9LmVwcmVkLnVwcGVyLCB4PXllYXIyLCBmaWxsPSJDb3VudGVyZmFjdHVhbCIpLCBhbHBoYT0wLjUpICsKICBnZW9tX2xpbmUoZGF0YSA9IGFnZV9zZXhfY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHk9LmVwcmVkLCB4PXllYXIyLCBjb2xvdXI9IkNvdW50ZXJmYWN0dWFsIikpICsKICBnZW9tX2xpbmUoYWVzKHk9LmVwcmVkLCB4PXllYXIyLCBncm91cD1hY2ZfcGVyaW9kLCAgY29sb3VyPWFjZl9wZXJpb2QpKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgLCBhZXMoeT1jYXNlcywgeD15ZWFyMiwgc2hhcGU9YWNmX3BlcmlvZCksIHNpemU9MikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBnZ2g0eDo6ZmFjZXRfZ3JpZDIoYWdlfnNleCwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSIiKSArCiAgc2NhbGVfc2hhcGVfZGlzY3JldGUobmFtZT0iIikgKwogIGxhYnMoCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJDYXNlIG5vdGlmaWNhdGlvbnMgKG4pIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTE0KSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xNCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpICsKICBndWlkZXMoc2hhcGU9Im5vbmUiKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNy5wbmciKSwgaGVpZ2h0PTEwKQoKYGBgCgojIyMjIDkuMiBTdW1tYXJ5IG9mIGltcGFjdCBvZiBpbnRlcnZlbnRpb24KCihUaGlzIGFsbCBuZWVkcyB0aWR5aW5nIHVwIGFuZCBjaGVja2luZyAtIHRvIGRvISkKCjEuIHBlcmNlbnRhZ2UgaW5jcmVhc2UgaW4gQ05SLCBmcm9tIDE5NTYgdG8gMTk1NyAoaS5lLiBpbW1lZGlhdGUgQUNGIGVmZmVjdCkKCmBgYHtyfQoKbmQgPC0gbWRhdGFfYWdlX3NleCAlPiUKICBmaWx0ZXIoeWVhciAlaW4lIGMoMTk1NjoxOTU3KSkgJT4lCiAgc2VsZWN0KGFjZl9wZXJpb2QsIHlfbnVtLCBhZ2UsIHNleCkKCgphZ2Vfc2V4X2ltcGFjdF9vdXQgPC0gCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCwKICAgICAgICAgICAgICAgIG5ld2RhdGE9bmQpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgLmVwcmVkLCBhZ2UsIHNleCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGFjZl9wZXJpb2QsCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSAuZXByZWQsCiAgICAgICAgICAgICAgdmFsdWVzX2ZuID0gbGlzdCkgJT4lCiAgdW5uZXN0KCkgJT4lCiAgcmVuYW1lKHByZV9lcHJlZCA9IDMsCiAgICAgICAgIHBvc3RfZXByZWQgPSA0KSAlPiUKICBtdXRhdGUoYWNmX2RpZmYgPSBwb3N0X2VwcmVkLXByZV9lcHJlZCwKICAgICAgICAgYWNmX3JyID0gcG9zdF9lcHJlZC9wcmVfZXByZWQpICU+JQogIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICBtZWFuX3FpKGFjZl9kaWZmLCBhY2ZfcnIpIAoKYWdlX3NleF9pbXBhY3Rfb3V0ICU+JQogIG11dGF0ZV9pZihpcy5kb3VibGUsIH4gc2NhbGVzOjpudW1iZXIoeCA9IC4sIGFjY3VyYWN5ID0gMC4wMSwgYmlnLm1hcmsgPSAiLCIpKSAlPiUKICBkYXRhdGFibGUoKQogIApmM2EgPC0gYWdlX3NleF9pbXBhY3Rfb3V0ICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PWFjZl9yciwgeW1pbj1hY2ZfcnIubG93ZXIsIHltYXg9YWNmX3JyLnVwcGVyLCBncm91cD1zZXgsIAogICAgICAgICAgICAgICAgICAgICAgeD1hZ2UsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXgpLAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4yNSkpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTEpLCBsaW5ldHlwZT0yKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJwdXJwbGUiLCAiZGFya29yYW5nZSIpLCBuYW1lPSIiKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iUmVsYXRpdmUgbm90aWZpY2F0aW9ucyAoOTUlIFVJKVxuQUNGICgxOTU3KSB2cy4gQmVmb3JlIEFDRiAoMTk1NikiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCiAgCiAgCgpgYGAKCgoyLiBDaGFuZ2UgZnJvbSBwcmUtQUNGIHBlcmlvZCAoMTk1NiksIHRvIGZpcnN0IHllYXIgcG9zdC1BQ0YgKDE5NTgpCgoKYGBge3J9CgpuZCA8LSBtZGF0YV9hZ2Vfc2V4ICU+JQogIGZpbHRlcih5ZWFyICVpbiUgYygxOTU2LDE5NTgpKSAlPiUKICBzZWxlY3QoYWNmX3BlcmlvZCwgeV9udW0sIGFnZSwgc2V4KQoKI0RvIGl0IHdpdGggY2FsY3VsYXRpbmcgaW5jaWRlbmNlLCB0aGVuIHN1bWFtcmlzaW5nLgphZ2Vfc2V4X2ltcGFjdDIgPC1hZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgbmV3ZGF0YT1uZCkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdChhY2ZfcGVyaW9kLCAuZXByZWQsIGFnZSwgc2V4KSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYWNmX3BlcmlvZCwKICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IC5lcHJlZCwKICAgICAgICAgICAgICB2YWx1ZXNfZm4gPSBsaXN0KSAlPiUKICB1bm5lc3QoKSAlPiUKICByZW5hbWUocHJlX2VwcmVkID0gMywKICAgICAgICBwb3N0X2VwcmVkID0gNCkgJT4lCiAgbXV0YXRlKGFjZl9kaWZmID0gcG9zdF9lcHJlZC1wcmVfZXByZWQsCiAgICAgICAgIGFjZl9yciA9IHBvc3RfZXByZWQvcHJlX2VwcmVkKSAlPiUKICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgbWVhbl9xaShhY2ZfZGlmZiwgYWNmX3JyKSAKCmFnZV9zZXhfaW1wYWN0MiAlPiUKICBtdXRhdGVfaWYoaXMuZG91YmxlLCB+IHNjYWxlczo6bnVtYmVyKHggPSAuLCBhY2N1cmFjeSA9IDAuMDEsIGJpZy5tYXJrID0gIiwiKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmYzYiA8LSBhZ2Vfc2V4X2ltcGFjdDIgJT4lICAKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeT1hY2ZfcnIsIHltaW49YWNmX3JyLmxvd2VyLCB5bWF4PWFjZl9yci51cHBlciwgZ3JvdXA9c2V4LCAKICAgICAgICAgICAgICAgICAgICAgIHg9YWdlLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2V4KSwKICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMjUpKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0xKSwgbGluZXR5cGU9MikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygicHVycGxlIiwgImRhcmtvcmFuZ2UiKSwgbmFtZT0iIikgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IlJlbGF0aXZlIG5vdGlmaWNhdGlvbnMgKDk1JSBVSSlcbkFDRiAoMTk1OCkgdnMuIEJlZm9yZSBBQ0YgKDE5NTYpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKCmBgYAoKMy4gQ2hhbmdlIGluIHNsb3BlIChpLmUuIGRpZmZlcmVuY2UgaW4gbWVhbiBhbm51YWwgY2FzZSBub3RpZmljYXRpb24gcmF0ZSBwcmUtSW50ZXJ2ZW50aW9uIHZzLiBwb3N0LWludGVydmVudGlvbiwgYnkgd2FyZCkKCmBgYHtyfQoKYWdlX3NleF9pbXBhY3QzIDwtIG1kYXRhX2FnZV9zZXggJT4lCiAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWNmX3BlcmlvZCwgY2FzZXMsIGFnZSwgc2V4KSAlPiUKICBmaWx0ZXIoeWVhciE9MTk1NykgJT4lCiAgYWRkX2VwcmVkX2RyYXdzKG1fYWdlX3NleCkgJT4lCiAgZ3JvdXBfYnkoeWVhciwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpICU+JQogIG1lYW5fcWkoLmVwcmVkKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKG5feWVhcnMgPSBsZW5ndGgoeWVhciksIC5ieT1hY2ZfcGVyaW9kKSAlPiUKICBzdW1tYXJpc2UocGN0X2NoYW5nZV9lcHJlZF9vdmVyYWxsID0gKCgobGFzdCguZXByZWQpIC0gZmlyc3QoLmVwcmVkKSkvZmlyc3QoLmVwcmVkKSkpLAogICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX292ZXJhbGwgPSAoKChsYXN0KC5sb3dlcikgLSBmaXJzdCgubG93ZXIpKS9maXJzdCgubG93ZXIpKSksCiAgICAgICAgICAgIHBjdF9jaGFuZ2VfdXBwZXJfb3ZlcmFsbCA9ICgoKGxhc3QoLnVwcGVyKSAtIGZpcnN0KC51cHBlcikpL2ZpcnN0KC51cHBlcikpKSwKICAgIAogICAgICAgICAgICBwY3RfY2hhbmdlX2VwcmVkX2FubnVhbCA9ICgoKGxhc3QoLmVwcmVkKSAtIGZpcnN0KC5lcHJlZCkpL2ZpcnN0KC5lcHJlZCkpL25feWVhcnMpLAogICAgICAgICAgICBwY3RfY2hhbmdlX2xvd2VyX2FubnVhbCA9ICgoKGxhc3QoLmxvd2VyKSAtIGZpcnN0KC5sb3dlcikpL2ZpcnN0KC5sb3dlcikpL25feWVhcnMpLAogICAgICAgICAgICBwY3RfY2hhbmdlX3VwcGVyX2FubnVhbCA9ICgoKGxhc3QoLnVwcGVyKSAtIGZpcnN0KC51cHBlcikpL2ZpcnN0KC51cHBlcikpL25feWVhcnMpLAogICAgICAgICAgICAuYnkgPSBjKGFjZl9wZXJpb2QsIGFnZSwgc2V4KSkgJT4lCiAgZGlzdGluY3QoKQoKCmFnZV9zZXhfaW1wYWN0MyAlPiUKICBtdXRhdGVfaWYoaXMuZG91YmxlLCBwZXJjZW50KSAlPiUKICBkYXRhdGFibGUoKQoKZjNjIDwtIGFnZV9zZXhfaW1wYWN0MyAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0wKSwgbGluZXR5cGU9MikgKwogICAgZ2VvbV9wb2ludHJhbmdlKGFlcyh5PXBjdF9jaGFuZ2VfZXByZWRfYW5udWFsLCB5bWluPXBjdF9jaGFuZ2VfbG93ZXJfYW5udWFsLCB5bWF4PXBjdF9jaGFuZ2VfdXBwZXJfYW5udWFsLCBncm91cD1hY2ZfcGVyaW9kLCAKICAgICAgICAgICAgICAgICAgICAgIHg9YWdlLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWNmX3BlcmlvZCksIHNpemU9MC4xKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9cGVyY2VudCkgKwogIGZhY2V0X2dyaWQoLn5zZXgpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICIjNEQ2Q0ZBIikpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJNZWFuIGFubnVhbCByYXRlIG9mIGNoYW5nZSBpbiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlICg5NSUgVUkpXG4gQmVmb3JlIEFDRiAoMTk1MC0xOTU2KSB2cy4gYWZ0ZXIgQUNGICgxOTU4LTE5NjMpIiwKICAgICAgIGNvbG91cj0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKZjNjCgpgYGAKCgojIyMjIDkuMyBDb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbAoKYGBge3J9Cgpjb3VudGVyZmFjdF9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgc2VsZWN0KHllYXIsIGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkX2NvdW50ZXJmID0gLmVwcmVkKQogIAojQ2FsY3VhdGUgaW5jaWRlbmNlIHBlciBkcmF3LCB0aGVuIHN1bW1hcmlzZS4KICBwb3N0X2NoYW5nZV9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAKICAKICAjZm9yIHRoZSBvdmVyYWxsIHBlcmlvZApjb3VudGVyZmFjdF9vdmVyYWxsX2FnZV9zZXggPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IG1fYWdlX3NleCwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YV9hZ2Vfc2V4ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhZ2UsIHNleCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gImEuIHByZS1hY2YiKSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICBzZWxlY3QoYWdlLCBzZXgsIC5kcmF3LCAuZXByZWQpICAlPiUKICAgICAgZ3JvdXBfYnkoYWdlLCBzZXgsIC5kcmF3KSAlPiUKICAgICAgc3VtbWFyaXNlKC5lcHJlZF9jb3VudGVyZiA9IHN1bSguZXByZWQpKSAlPiUKICAgICAgbXV0YXRlKHllYXIgPSAiT3ZlcmFsbCAoMTk1OC0xOTYzKSIpCiAgCiAgI0NhbGN1YXRlIGluY2lkZW5jZSBwZXIgZHJhdywgdGhlbiBzdW1tYXJpc2UuCiAgcG9zdF9jaGFuZ2Vfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdChhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCBhZ2UsIHNleCkgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWQgPSBzdW0oLmVwcmVkKSkgCiAgCiAgCgpsZWZ0X2pvaW4oY291bnRlcmZhY3RfYWdlX3NleCwgcG9zdF9jaGFuZ2VfYWdlX3NleCkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZikgJT4lCiAgICBncm91cF9ieSh5ZWFyLCBhZ2UsIHNleCkgJT4lCiAgICBtZWFuX3FpKGNhc2VzX2F2ZXJ0ZWQsIHBjdF9jaGFuZ2UpICU+JQogICAgdW5ncm91cCgpICU+JQogIGRhdGF0YWJsZSgpCgpjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgbGVmdF9qb2luKGNvdW50ZXJmYWN0X292ZXJhbGxfYWdlX3NleCwgcG9zdF9jaGFuZ2Vfb3ZlcmFsbF9hZ2Vfc2V4KSAlPiUKICAgIG11dGF0ZShjYXNlc19hdmVydGVkID0gLmVwcmVkX2NvdW50ZXJmLS5lcHJlZCwKICAgICAgICAgICBwY3RfY2hhbmdlID0gKC5lcHJlZCAtIC5lcHJlZF9jb3VudGVyZikvLmVwcmVkX2NvdW50ZXJmKSAlPiUKICAgIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICAgIG1lYW5fcWkoY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUoeWVhciA9ICJPdmVyYWxsICgxOTU4LTE5NjMpIikgCgoKYGBgCgoKYGBge3J9CgphZ2Vfc2V4X3R4dCA8LSBjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgdHJhbnNtdXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIHNleCA9IHNleCwKICAgICAgICAgICAgYWdlID0gYWdlLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9XG4oe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfVxuKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIikpCgoKYWdlX3NleF90eHQgJT4lIGRhdGF0YWJsZSgpCgoKYGBgCgpgYGB7cn0KCmYzZCA8LSBjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4ICU+JSAKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeCA9IGFnZSwgeT1jYXNlc19hdmVydGVkLCB5bWluPWNhc2VzX2F2ZXJ0ZWQubG93ZXIsIHltYXg9Y2FzZXNfYXZlcnRlZC51cHBlciwgY29sb3VyPXNleCkpICsgCiAgZmFjZXRfZ3JpZCgufnNleCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJwdXJwbGUiLCAiZGFya29yYW5nZSIpLCBuYW1lPSIiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iTnVtYmVyICg5NSUgVUkpIG9mIFRCIGNhc2VzIGF2ZXJ0ZWQgKDE5NTgtMTk2MykiLAogICAgICAgY29sb3VyPSIiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZjNkCmBgYAoKCgoKSm9pbiB0b2dldGhlciBmb3IgRmlndXJlIDIuCgoKYGBge3J9CgooZjNhICsgZjNiKSAvIChmM2MgKyBmM2QpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMy5wbmciKSwgd2lkdGggPSAxMikKCgpgYGAKbWRhdGFfYWdlX3NleA==